@h-ai/api-client 0.1.0-alpha.13 → 0.1.0-alpha.16

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api-client-auth.ts","../messages/en-US.json","../messages/zh-CN.json","../src/api-client-i18n.ts","../src/api-client-types.ts","../src/api-client-contract.ts","../src/api-client-error.ts","../src/api-client-fetch.ts","../src/api-client-token-manager.ts","../src/api-client-main.ts"],"names":["core","err","ok","logger","TRAILING_SLASHES_REGEX"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @h-ai/api-client — Token 存储适配器\n *\n * 提供 localStorage 和内存两种内置 Token 存储实现。\n * @module api-client-auth\n */\n\nimport type { TokenStorage } from './api-client-types.js'\n\n// ─── localStorage 存储 ───\n\nconst LS_ACCESS_KEY = 'hai_access_token'\nconst LS_REFRESH_KEY = 'hai_refresh_token'\n\n/**\n * 创建基于 localStorage 的 Token 存储\n *\n * 适用于浏览器端 SPA / PWA。Capacitor 环境建议使用\n * `@h-ai/capacitor` 提供的 `CapacitorTokenStorage`。\n *\n * @returns TokenStorage 实例\n *\n * @example\n * ```ts\n * import { api, createLocalStorageTokenStorage } from '@h-ai/api-client'\n *\n * await api.init({\n * baseUrl: 'https://api.example.com',\n * auth: {\n * storage: createLocalStorageTokenStorage(),\n * refreshUrl: '/auth/refresh',\n * },\n * })\n * ```\n */\nexport function createLocalStorageTokenStorage(): TokenStorage {\n return {\n async getAccessToken() {\n return globalThis.localStorage?.getItem(LS_ACCESS_KEY) ?? null\n },\n async setAccessToken(token: string) {\n globalThis.localStorage?.setItem(LS_ACCESS_KEY, token)\n },\n async getRefreshToken() {\n return globalThis.localStorage?.getItem(LS_REFRESH_KEY) ?? null\n },\n async setRefreshToken(token: string) {\n globalThis.localStorage?.setItem(LS_REFRESH_KEY, token)\n },\n async clear() {\n globalThis.localStorage?.removeItem(LS_ACCESS_KEY)\n globalThis.localStorage?.removeItem(LS_REFRESH_KEY)\n },\n }\n}\n\n// ─── 内存存储 ───\n\n/**\n * 创建内存 Token 存储\n *\n * 适用于 Node.js 测试、SSR 或短生命周期场景。\n * 页面刷新后 Token 丢失。\n *\n * @returns TokenStorage 实例\n *\n * @example\n * ```ts\n * import { api, createMemoryTokenStorage } from '@h-ai/api-client'\n *\n * await api.init({\n * baseUrl: 'https://api.example.com',\n * auth: {\n * storage: createMemoryTokenStorage(),\n * refreshUrl: '/auth/refresh',\n * },\n * })\n * ```\n */\nexport function createMemoryTokenStorage(): TokenStorage {\n let accessToken: string | null = null\n let refreshToken: string | null = null\n\n return {\n async getAccessToken() {\n return accessToken\n },\n async setAccessToken(token: string) {\n accessToken = token\n },\n async getRefreshToken() {\n return refreshToken\n },\n async setRefreshToken(token: string) {\n refreshToken = token\n },\n async clear() {\n accessToken = null\n refreshToken = null\n },\n }\n}\n","{\n \"apiClient_networkError\": \"Network request failed\",\n \"apiClient_timeout\": \"Request timeout\",\n \"apiClient_serverError\": \"Server error ({status})\",\n \"apiClient_unauthorized\": \"Unauthorized, please log in again\",\n \"apiClient_forbidden\": \"Access forbidden\",\n \"apiClient_notFound\": \"Resource not found\",\n \"apiClient_validationFailed\": \"Request validation failed\",\n \"apiClient_tokenRefreshFailed\": \"Token refresh failed, please log in again\",\n \"apiClient_notInitialized\": \"API client not initialized, please call api.init() first\",\n \"apiClient_configError\": \"API client config error: {error}\",\n \"apiClient_responseValidationFailed\": \"Response validation failed\",\n \"apiClient_unknown\": \"Unknown error\"\n}\n","{\n \"apiClient_networkError\": \"网络请求失败\",\n \"apiClient_timeout\": \"请求超时\",\n \"apiClient_serverError\": \"服务器错误({status})\",\n \"apiClient_unauthorized\": \"未授权,请重新登录\",\n \"apiClient_forbidden\": \"无权限访问\",\n \"apiClient_notFound\": \"请求的资源不存在\",\n \"apiClient_validationFailed\": \"请求参数校验失败\",\n \"apiClient_tokenRefreshFailed\": \"Token刷新失败,请重新登录\",\n \"apiClient_notInitialized\": \"API 客户端未初始化,请先调用 api.init()\",\n \"apiClient_configError\": \"API 客户端配置错误:{error}\",\n \"apiClient_responseValidationFailed\": \"响应数据校验失败\",\n \"apiClient_unknown\": \"未知错误\"\n}\n","/**\n * @h-ai/api-client — i18n\n *\n * 模块 i18n 文案访问入口。\n * @module api-client-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\ntype ApiClientMessageKey = keyof typeof messagesZhCN\n\n/**\n * api-client 模块 i18n 文案获取器\n *\n * @param key - 文案 Key\n * @param options - 插值参数\n * @returns 本地化后的文案字符串\n */\nexport const apiClientM = core.i18n.createMessageGetter<ApiClientMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n})\n","/**\n * @h-ai/api-client — 类型定义\n *\n * 通用 HTTP 客户端的公共类型、EndpointDef 契约接口、\n * TokenStorage 适配器接口等。\n * @module api-client-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport type { z } from 'zod'\nimport { core } from '@h-ai/core'\n\n// ─── 错误定义(照 @h-ai/core 范式) ───\n\nconst ApiClientErrorInfo = {\n NETWORK_ERROR: '001:502',\n TIMEOUT: '002:504',\n SERVER_ERROR: '003:502',\n UNAUTHORIZED: '004:401',\n FORBIDDEN: '005:403',\n NOT_FOUND: '006:404',\n VALIDATION_FAILED: '007:400',\n TOKEN_REFRESH_FAILED: '008:401',\n NOT_INITIALIZED: '010:500',\n CONFIG_ERROR: '011:500',\n UNKNOWN: '099:500',\n} as const satisfies ErrorInfo\n\nexport const HaiApiClientError = core.error.buildHaiErrorsDef('api-client', ApiClientErrorInfo)\n\n// ─── API 契约 ───\n\n/**\n * API 端点契约定义\n *\n * 描述单个 API 端点的 HTTP 方法、路径、入参/出参 Schema 与元数据。\n * 客户端通过 `api.call(endpoint, input)` 调用,服务端通过\n * `kit.fromContract(endpoint, handler)` 响应,两端共享同一份契约。\n *\n * @typeParam TInput - 入参类型(由 Zod Schema 推导)\n * @typeParam TOutput - 出参类型(由 Zod Schema 推导)\n *\n * @example\n * ```ts\n * const loginEndpoint: EndpointDef<LoginInput, LoginOutput> = {\n * method: 'POST',\n * path: '/auth/login',\n * input: LoginInputSchema,\n * output: LoginOutputSchema,\n * requireAuth: false,\n * }\n * ```\n */\nexport interface EndpointDef<\n TInput = unknown,\n TOutput = unknown,\n> {\n /** HTTP 方法 */\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'\n /** 相对路径(相对于 API 前缀,如 '/auth/login') */\n path: string\n /** 入参 Zod Schema(GET 请求为 query params,其他为 body) */\n input: z.ZodType<TInput>\n /** 出参 Zod Schema */\n output: z.ZodType<TOutput>\n /** 是否需要认证(默认 true) */\n requireAuth?: boolean\n /** OpenAPI 描述元数据 */\n meta?: {\n summary?: string\n tags?: string[]\n }\n}\n\n// ─── Token ───\n\n/**\n * Token 对(与 @h-ai/iam 的 TokenPair 对齐)\n */\nexport interface TokenPair {\n /** Access Token */\n accessToken: string\n /** Refresh Token */\n refreshToken: string\n /** 过期时间(秒) */\n expiresIn: number\n /** Token 类型 */\n tokenType: 'Bearer'\n}\n\n/**\n * Token 存储适配器\n *\n * 可插拔存储后端(localStorage / memory / Capacitor Preferences / 自定义)。\n */\nexport interface TokenStorage {\n /** 获取 Access Token */\n getAccessToken: () => Promise<string | null>\n /** 设置 Access Token */\n setAccessToken: (token: string) => Promise<void>\n /** 获取 Refresh Token */\n getRefreshToken: () => Promise<string | null>\n /** 设置 Refresh Token */\n setRefreshToken: (token: string) => Promise<void>\n /** 清空所有 Token */\n clear: () => Promise<void>\n}\n\n// ─── 拦截器 ───\n\n/**\n * 请求配置(传递给拦截器)\n */\nexport interface RequestConfig {\n /** 完整 URL */\n url: string\n /** HTTP 方法 */\n method: string\n /** 请求头 */\n headers: Record<string, string>\n /** 请求体(已序列化) */\n body?: string | FormData\n /** 信号(abort) */\n signal?: AbortSignal\n}\n\n/** 请求拦截器 */\nexport type RequestInterceptor = (config: RequestConfig) => RequestConfig | Promise<RequestConfig>\n\n/** 响应拦截器 */\nexport type ResponseInterceptor = (response: Response) => Response | Promise<Response>\n\n// ─── 配置 ───\n\n/**\n * Token 刷新配置\n */\nexport interface AuthConfig {\n /** Token 存储适配器(默认 createLocalStorageTokenStorage) */\n storage?: TokenStorage\n /** Refresh Token 接口路径(相对于 baseUrl) */\n refreshUrl: string\n /** Token 刷新回调 */\n onTokenRefreshed?: (tokens: TokenPair) => void\n /** Token 刷新失败回调(通常用于跳转登录页) */\n onRefreshFailed?: () => void\n}\n\n/**\n * ApiClient 配置\n */\nexport interface ApiClientConfig {\n /** API 基础 URL(如 https://api.example.com/api/v1) */\n baseUrl: string\n /** Token 认证配置(省略则不启用自动 Token 管理) */\n auth?: AuthConfig\n /** 请求超时(毫秒,默认 30000) */\n timeout?: number\n /** 拦截器 */\n interceptors?: {\n request?: RequestInterceptor[]\n response?: ResponseInterceptor[]\n }\n /** 自定义 fetch 实现(用于测试或特殊环境) */\n fetch?: typeof globalThis.fetch\n}\n\n// ─── 上传选项 ───\n\n/**\n * 文件上传选项\n */\nexport interface UploadOptions {\n /** 文件字段名(默认 'file') */\n fieldName?: string\n /** 附加表单字段 */\n extraFields?: Record<string, string>\n}\n\n/**\n * 流式请求选项\n */\nexport interface StreamOptions {\n /** 外部取消信号(例如 AbortController.signal) */\n signal?: AbortSignal\n}\n\n// ─── ApiClient 接口 ───\n\n/**\n * Api Client 实例接口\n *\n * 提供通用 HTTP 方法和契约调用能力。\n */\nexport interface ApiClient {\n /** GET 请求 */\n get: <T>(path: string, params?: Record<string, unknown>) => Promise<HaiResult<T>>\n /** POST 请求 */\n post: <T>(path: string, body?: unknown) => Promise<HaiResult<T>>\n /** PUT 请求 */\n put: <T>(path: string, body?: unknown) => Promise<HaiResult<T>>\n /** PATCH 请求 */\n patch: <T>(path: string, body?: unknown) => Promise<HaiResult<T>>\n /** DELETE 请求 */\n delete: <T>(path: string, params?: Record<string, unknown>) => Promise<HaiResult<T>>\n\n /** 文件上传 */\n upload: (path: string, file: File | Blob, options?: UploadOptions) => Promise<HaiResult<unknown>>\n\n /** 流式请求(返回 AsyncIterable) */\n stream: (path: string, body?: unknown, options?: StreamOptions) => AsyncIterable<string>\n\n /**\n * 契约调用(推荐)\n *\n * 基于 EndpointDef 发起请求,路径、方法、入参、出参类型全由契约保证。\n */\n call: <TInput, TOutput>(\n endpoint: EndpointDef<TInput, TOutput>,\n input: TInput,\n ) => Promise<HaiResult<TOutput>>\n\n /** Token 管理 */\n auth: {\n /** 设置 Token */\n setTokens: (tokens: TokenPair) => Promise<void>\n /** 清空 Token */\n clear: () => Promise<void>\n /** Token 刷新回调,返回取消订阅函数 */\n onTokenRefreshed: (callback: (tokens: TokenPair) => void) => () => void\n }\n}\n\n/**\n * 辅助函数:创建端点定义(获得类型推导)\n *\n * @example\n * ```ts\n * const login = defineEndpoint({\n * method: 'POST',\n * path: '/auth/login',\n * input: LoginInputSchema,\n * output: LoginOutputSchema,\n * requireAuth: false,\n * })\n * ```\n */\nexport function defineEndpoint<TInput, TOutput>(\n def: EndpointDef<TInput, TOutput>,\n): EndpointDef<TInput, TOutput> {\n return def\n}\n\n// ─── ApiClientFunctions ───\n\n/**\n * API 客户端函数接口(单例模式)\n *\n * 统一的 API 客户端访问入口:\n * - `api.init(config)` — 初始化客户端\n * - `api.close()` — 关闭客户端并释放资源\n * - `api.get / post / put / patch / delete` — 通用 HTTP 方法\n * - `api.call(endpoint, input)` — 契约调用\n * - `api.upload(path, file)` — 文件上传\n * - `api.stream(path, body)` — 流式请求\n * - `api.auth` — Token 管理\n * - `api.config` — 当前配置(未初始化时为 null)\n * - `api.isInitialized` — 初始化状态\n */\nexport interface ApiClientFunctions {\n /**\n * 初始化 API 客户端\n *\n * 已有实例时会先 close 再重新初始化。\n *\n * @param config - 客户端配置\n * @returns 成功 ok(undefined);失败返回 err(含 ApiClientError)\n */\n init: (config: ApiClientConfig) => Promise<HaiResult<void>>\n\n /**\n * 关闭 API 客户端并释放资源\n *\n * 重复调用不会报错。\n */\n close: () => Promise<void>\n\n /** 当前客户端配置;未初始化或已关闭时为 null */\n readonly config: ApiClientConfig | null\n\n /** 是否已完成初始化 */\n readonly isInitialized: boolean\n\n /** GET 请求 */\n readonly get: ApiClient['get']\n /** POST 请求 */\n readonly post: ApiClient['post']\n /** PUT 请求 */\n readonly put: ApiClient['put']\n /** PATCH 请求 */\n readonly patch: ApiClient['patch']\n /** DELETE 请求 */\n readonly delete: ApiClient['delete']\n /** 文件上传 */\n readonly upload: ApiClient['upload']\n\n /**\n * 流式请求(返回 AsyncIterable)\n *\n * @throws 未初始化时抛出异常(async generator 无法返回 HaiResult)\n */\n readonly stream: ApiClient['stream']\n\n /** 契约调用(推荐) */\n readonly call: ApiClient['call']\n\n /** Token 管理 */\n readonly auth: ApiClient['auth']\n}\n","/**\n * @h-ai/api-client — 契约调用\n *\n * 基于 EndpointDef 发起类型安全的 API 请求。\n * @module api-client-contract\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { FetchClient } from './api-client-fetch.js'\nimport type { EndpointDef } from './api-client-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { apiClientM } from './api-client-i18n.js'\nimport { HaiApiClientError } from './api-client-types.js'\n\n/**\n * 创建契约调用函数\n *\n * @param fetchClient - Fetch Client 实例\n * @returns call 函数\n */\nexport function createContractCaller(fetchClient: FetchClient) {\n /**\n * 基于端点契约发起请求\n *\n * 路径、方法、入参、出参类型全由契约保证。\n *\n * @typeParam TInput - 入参类型\n * @typeParam TOutput - 出参类型\n * @param endpoint - 端点契约定义\n * @param input - 入参数据\n * @returns 出参 HaiResult\n *\n * @example\n * ```ts\n * const result = await api.call(iamEndpoints.login, { identifier: 'alice', password: 'xxx' })\n * ```\n */\n async function call<TInput, TOutput>(\n endpoint: EndpointDef<TInput, TOutput>,\n input: TInput,\n ): Promise<HaiResult<TOutput>> {\n // 客户端入参校验(避免无效请求发送到服务端)\n const parsed = endpoint.input.safeParse(input)\n if (!parsed.success) {\n return err(\n HaiApiClientError.VALIDATION_FAILED,\n apiClientM('apiClient_validationFailed'),\n parsed.error.issues,\n )\n }\n\n const validInput = parsed.data\n\n let result: HaiResult<unknown>\n\n switch (endpoint.method) {\n case 'GET':\n result = await fetchClient.get(endpoint.path, validInput as Record<string, unknown>)\n break\n\n case 'POST':\n result = await fetchClient.post(endpoint.path, validInput)\n break\n\n case 'PUT':\n result = await fetchClient.put(endpoint.path, validInput)\n break\n\n case 'PATCH':\n result = await fetchClient.patch(endpoint.path, validInput)\n break\n\n case 'DELETE':\n result = await fetchClient.delete(endpoint.path, validInput as Record<string, unknown>)\n break\n\n default:\n return err(\n HaiApiClientError.UNKNOWN,\n apiClientM('apiClient_unknown'),\n )\n }\n\n if (!result.success) {\n return result\n }\n\n // 响应数据校验(确保服务端返回的数据符合契约)\n const outputParsed = endpoint.output.safeParse(result.data)\n if (!outputParsed.success) {\n return err(\n HaiApiClientError.VALIDATION_FAILED,\n apiClientM('apiClient_responseValidationFailed'),\n outputParsed.error.issues,\n )\n }\n\n return ok(outputParsed.data)\n }\n\n return call\n}\n","/**\n * @h-ai/api-client — 错误处理\n *\n * HTTP 状态码到 HaiResult 错误的统一转换。\n * @module api-client-error\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport { err } from '@h-ai/core'\nimport { apiClientM } from './api-client-i18n.js'\nimport { HaiApiClientError } from './api-client-types.js'\n\n/**\n * 将 HTTP 响应转为 HaiResult<never>\n *\n * @param response - HTTP 响应\n * @returns HaiResult<never>\n */\nexport async function responseToError(response: Response): Promise<HaiResult<never>> {\n let details: unknown\n\n try {\n const body = await response.json()\n details = body\n }\n catch {\n // 响应体不是 JSON,忽略\n }\n\n const status = response.status\n\n if (status === 401) {\n return err(\n HaiApiClientError.UNAUTHORIZED,\n apiClientM('apiClient_unauthorized'),\n details,\n )\n }\n\n if (status === 403) {\n return err(\n HaiApiClientError.FORBIDDEN,\n apiClientM('apiClient_forbidden'),\n details,\n )\n }\n\n if (status === 404) {\n return err(\n HaiApiClientError.NOT_FOUND,\n apiClientM('apiClient_notFound'),\n details,\n )\n }\n\n if (status === 400 || status === 422) {\n return err(\n HaiApiClientError.VALIDATION_FAILED,\n apiClientM('apiClient_validationFailed'),\n details,\n )\n }\n\n if (status >= 500) {\n return err(\n HaiApiClientError.SERVER_ERROR,\n apiClientM('apiClient_serverError', { params: { status: String(status) } }),\n details,\n )\n }\n\n return err(\n HaiApiClientError.UNKNOWN,\n apiClientM('apiClient_unknown'),\n details,\n )\n}\n\n/**\n * 将网络异常转为 HaiResult<never>\n *\n * @param cause - 原始异常\n * @returns HaiResult<never>\n */\nexport function networkErrorToResult(cause: unknown): HaiResult<never> {\n // AbortError = 超时\n if (cause instanceof DOMException && cause.name === 'AbortError') {\n return err(\n HaiApiClientError.TIMEOUT,\n apiClientM('apiClient_timeout'),\n cause,\n )\n }\n\n return err(\n HaiApiClientError.NETWORK_ERROR,\n apiClientM('apiClient_networkError'),\n cause,\n )\n}\n","/**\n * @h-ai/api-client — 核心 fetch 封装\n *\n * 请求/响应拦截器链、超时控制、Token 自动附加、401 自动刷新重试。\n * @module api-client-fetch\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { TokenManager } from './api-client-token-manager.js'\nimport type {\n ApiClientConfig,\n RequestConfig,\n RequestInterceptor,\n ResponseInterceptor,\n StreamOptions,\n UploadOptions,\n} from './api-client-types.js'\nimport { core, ok } from '@h-ai/core'\nimport { networkErrorToResult, responseToError } from './api-client-error.js'\nimport { apiClientM } from './api-client-i18n.js'\n\nconst logger = core.logger.child({ module: 'api-client', scope: 'fetch' })\n\n/** 默认超时 30s */\nconst DEFAULT_TIMEOUT = 30_000\nconst TRAILING_SLASHES_REGEX = /\\/+$/\n\n/**\n * 创建核心请求函数\n *\n * 封装 fetch 请求,集成:\n * - 请求/响应拦截器链\n * - 超时控制(AbortController)\n * - Token 自动附加(Authorization: Bearer)\n * - 401 自动刷新 + 重试(一次)\n *\n * @param config - ApiClient 配置\n * @param tokenManager - Token 管理器(可选)\n * @returns 请求函数集合\n */\nexport function createFetchClient(\n config: ApiClientConfig,\n tokenManager?: TokenManager,\n) {\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis)\n const timeout = config.timeout ?? DEFAULT_TIMEOUT\n const requestInterceptors: RequestInterceptor[] = config.interceptors?.request ?? []\n const responseInterceptors: ResponseInterceptor[] = config.interceptors?.response ?? []\n\n /**\n * 构建完整 URL\n */\n function buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = config.baseUrl.replace(TRAILING_SLASHES_REGEX, '')\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n const url = new URL(`${base}${normalizedPath}`)\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n return url.toString()\n }\n\n /**\n * 执行请求(含拦截器、超时、Token、401 重试)\n */\n async function execute<T>(\n requestConfig: RequestConfig,\n retryOnUnauthorized = true,\n ): Promise<HaiResult<T>> {\n logger.trace('Executing request', { method: requestConfig.method, url: requestConfig.url })\n\n // 1. Token 注入\n if (tokenManager) {\n const accessToken = await tokenManager.storage.getAccessToken()\n if (accessToken) {\n requestConfig.headers.Authorization = `Bearer ${accessToken}`\n }\n }\n\n // 2. 请求拦截器\n let finalConfig = requestConfig\n for (const interceptor of requestInterceptors) {\n finalConfig = await interceptor(finalConfig)\n }\n\n // 3. 超时控制\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n finalConfig.signal = controller.signal\n\n try {\n let response = await fetchFn(finalConfig.url, {\n method: finalConfig.method,\n headers: finalConfig.headers,\n body: finalConfig.body,\n signal: finalConfig.signal,\n })\n\n clearTimeout(timeoutId)\n\n // 4. 响应拦截器\n for (const interceptor of responseInterceptors) {\n response = await interceptor(response)\n }\n\n // 5. 401 自动刷新 + 重试\n if (response.status === 401 && retryOnUnauthorized && tokenManager) {\n logger.trace('Received 401, attempting token refresh', { url: requestConfig.url })\n const tokens = await tokenManager.refresh()\n if (tokens) {\n logger.trace('Token refreshed, retrying request', { url: requestConfig.url })\n requestConfig.headers.Authorization = `Bearer ${tokens.accessToken}`\n return execute<T>(requestConfig, false)\n }\n logger.warn('Token refresh failed, returning 401 error', { url: requestConfig.url })\n }\n\n // 6. 错误处理\n if (!response.ok) {\n return responseToError(response)\n }\n\n // 7. 解析成功响应\n const contentType = response.headers.get('content-type') ?? ''\n if (contentType.includes('application/json')) {\n const body = await response.json() as { data?: T, success?: boolean }\n // 兼容标准 HaiResult 响应格式 { success, data }\n if (body && typeof body === 'object' && 'data' in body) {\n return ok(body.data as T)\n }\n return ok(body as T)\n }\n\n // 非 JSON 响应(204 No Content 等)\n return ok(undefined as T)\n }\n catch (cause) {\n clearTimeout(timeoutId)\n logger.warn('Request failed', { url: requestConfig.url, error: cause })\n return networkErrorToResult(cause)\n }\n }\n\n // ─── 通用 HTTP 方法 ───\n\n async function get<T>(path: string, params?: Record<string, unknown>): Promise<HaiResult<T>> {\n return execute<T>({\n url: buildUrl(path, params),\n method: 'GET',\n headers: { Accept: 'application/json' },\n })\n }\n\n async function post<T>(path: string, body?: unknown): Promise<HaiResult<T>> {\n return execute<T>({\n url: buildUrl(path),\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n }\n\n async function put<T>(path: string, body?: unknown): Promise<HaiResult<T>> {\n return execute<T>({\n url: buildUrl(path),\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n }\n\n async function patch<T>(path: string, body?: unknown): Promise<HaiResult<T>> {\n return execute<T>({\n url: buildUrl(path),\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n }\n\n async function del<T>(path: string, params?: Record<string, unknown>): Promise<HaiResult<T>> {\n return execute<T>({\n url: buildUrl(path, params),\n method: 'DELETE',\n headers: { Accept: 'application/json' },\n })\n }\n\n // ─── 文件上传 ───\n\n async function upload(\n path: string,\n file: File | Blob,\n options?: UploadOptions,\n ): Promise<HaiResult<unknown>> {\n const formData = new FormData()\n formData.append(options?.fieldName ?? 'file', file)\n\n if (options?.extraFields) {\n for (const [key, value] of Object.entries(options.extraFields)) {\n formData.append(key, value)\n }\n }\n\n return execute({\n url: buildUrl(path),\n method: 'POST',\n headers: { Accept: 'application/json' },\n body: formData,\n })\n }\n\n // ─── 流式请求 ───\n\n async function* stream(path: string, body?: unknown, options?: StreamOptions): AsyncIterable<string> {\n const requestConfig: RequestConfig = {\n url: buildUrl(path),\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n }\n\n // Token 注入\n if (tokenManager) {\n const accessToken = await tokenManager.storage.getAccessToken()\n if (accessToken) {\n requestConfig.headers.Authorization = `Bearer ${accessToken}`\n }\n }\n\n // 请求拦截器\n let finalConfig = requestConfig\n for (const interceptor of requestInterceptors) {\n finalConfig = await interceptor(finalConfig)\n }\n\n // 超时控制 + 外部 abort\n const controller = new AbortController()\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n let timeoutTriggered = false\n\n const clearStreamTimeout = () => {\n if (timeoutId) {\n clearTimeout(timeoutId)\n timeoutId = null\n }\n }\n\n const armStreamTimeout = () => {\n clearStreamTimeout()\n timeoutTriggered = false\n timeoutId = setTimeout(() => {\n timeoutTriggered = true\n controller.abort()\n }, timeout)\n }\n\n const externalSignal = options?.signal\n const onExternalAbort = () => {\n controller.abort()\n }\n\n if (externalSignal) {\n if (externalSignal.aborted) {\n controller.abort()\n }\n else {\n externalSignal.addEventListener('abort', onExternalAbort, { once: true })\n }\n }\n\n async function doStreamFetch(): Promise<Response> {\n armStreamTimeout()\n try {\n return await fetchFn(finalConfig.url, {\n method: finalConfig.method,\n headers: finalConfig.headers,\n body: finalConfig.body,\n signal: controller.signal,\n })\n }\n catch (cause) {\n clearStreamTimeout()\n throw cause\n }\n }\n\n // 统一资源清理:无论 doStreamFetch / 401 重试 / 读取阶段在哪抛出异常,\n // 都确保清理超时定时器、外部信号监听器和 reader 锁。\n let reader: ReadableStreamDefaultReader<Uint8Array> | null = null\n\n try {\n let response = await doStreamFetch()\n\n // 401 自动刷新 + 重试(一次)\n if (response.status === 401 && tokenManager) {\n logger.info('Stream received 401, attempting token refresh', { url: requestConfig.url })\n const tokens = await tokenManager.refresh()\n if (tokens) {\n finalConfig.headers.Authorization = `Bearer ${tokens.accessToken}`\n response = await doStreamFetch()\n }\n }\n\n if (!response.ok) {\n const errorResult = await responseToError(response)\n if (!errorResult.success) {\n throw new Error(errorResult.error.message, { cause: errorResult.error })\n }\n }\n\n if (!response.body) {\n throw new Error(apiClientM('apiClient_networkError'))\n }\n\n reader = response.body.getReader()\n const decoder = new TextDecoder()\n let lineBuffer = ''\n\n while (true) {\n armStreamTimeout()\n const { done, value } = await reader.read()\n clearStreamTimeout()\n if (done)\n break\n\n lineBuffer += decoder.decode(value, { stream: true })\n // 按换行分割,保留最后一段(可能是不完整行)\n const parts = lineBuffer.split('\\n')\n lineBuffer = parts.pop() ?? ''\n\n for (const line of parts) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6)\n if (data !== '[DONE]') {\n yield data\n }\n }\n }\n }\n\n // 处理缓冲区剩余内容\n if (lineBuffer.startsWith('data: ')) {\n const data = lineBuffer.slice(6)\n if (data !== '[DONE]') {\n yield data\n }\n }\n }\n catch (cause) {\n if (cause instanceof DOMException && cause.name === 'AbortError') {\n if (externalSignal?.aborted && !timeoutTriggered) {\n throw cause\n }\n throw new Error(apiClientM('apiClient_timeout'), { cause })\n }\n throw cause\n }\n finally {\n clearStreamTimeout()\n if (externalSignal) {\n externalSignal.removeEventListener('abort', onExternalAbort)\n }\n if (reader) {\n reader.releaseLock()\n }\n }\n }\n\n return { get, post, put, patch, delete: del, upload, stream, execute, buildUrl }\n}\n\n/** Fetch Client 类型 */\nexport type FetchClient = ReturnType<typeof createFetchClient>\n","/**\n * @h-ai/api-client — Token 管理器(内部)\n *\n * 管理 Token 存储和自动刷新逻辑,仅供模块内部使用,不对外导出。\n * @module api-client-token-manager\n * @internal\n */\n\nimport type { TokenPair, TokenStorage } from './api-client-types.js'\nimport { core } from '@h-ai/core'\nimport { z } from 'zod'\n\nconst logger = core.logger.child({ module: 'api-client', scope: 'auth' })\n\n/**\n * Token 刷新响应校验 Schema\n */\nconst TokenPairSchema = z.object({\n accessToken: z.string().min(1),\n refreshToken: z.string().min(1),\n expiresIn: z.number().optional(),\n tokenType: z.string().optional(),\n})\n\n/**\n * Token 刷新回调\n */\ntype RefreshCallback = (tokens: TokenPair) => void\n\n/**\n * 创建 Token 管理器\n *\n * 内部使用,管理 Token 存储和刷新逻辑。\n *\n * @param storage - Token 存储适配器\n * @param refreshUrl - Refresh Token 接口完整 URL\n * @param fetchFn - fetch 实现\n * @param onRefreshFailed - 刷新失败回调\n * @returns Token 管理器\n */\nexport function createTokenManager(\n storage: TokenStorage,\n refreshUrl: string,\n fetchFn: typeof globalThis.fetch,\n onRefreshFailed?: () => void,\n) {\n const callbacks: RefreshCallback[] = []\n let refreshPromise: Promise<TokenPair | null> | null = null\n\n /**\n * 刷新 Token(带并发去重)\n *\n * 多个并发 401 只发一次 refresh 请求。\n */\n async function refresh(): Promise<TokenPair | null> {\n // 去重:已有刷新请求进行中,复用\n if (refreshPromise) {\n return refreshPromise\n }\n\n refreshPromise = doRefresh()\n try {\n return await refreshPromise\n }\n finally {\n refreshPromise = null\n }\n }\n\n async function doRefresh(): Promise<TokenPair | null> {\n const refreshToken = await storage.getRefreshToken()\n if (!refreshToken) {\n logger.warn('Token refresh skipped, no refresh token available')\n onRefreshFailed?.()\n return null\n }\n\n logger.debug('Refreshing token', { url: refreshUrl })\n\n try {\n const response = await fetchFn(refreshUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken }),\n })\n\n if (!response.ok) {\n await storage.clear()\n onRefreshFailed?.()\n return null\n }\n\n const body = await response.json() as { data?: unknown }\n const parsed = TokenPairSchema.safeParse(body.data)\n if (!parsed.success) {\n logger.warn('Token refresh returned invalid data', { issues: parsed.error.issues })\n await storage.clear()\n onRefreshFailed?.()\n return null\n }\n\n // 提供默认值,避免 as TokenPair 不安全强转\n const tokens: TokenPair = {\n accessToken: parsed.data.accessToken,\n refreshToken: parsed.data.refreshToken,\n expiresIn: parsed.data.expiresIn ?? 3600,\n tokenType: 'Bearer',\n }\n await storage.setAccessToken(tokens.accessToken)\n await storage.setRefreshToken(tokens.refreshToken)\n logger.info('Token refreshed successfully')\n\n // 通知回调\n for (const cb of callbacks) {\n cb(tokens)\n }\n\n return tokens\n }\n catch (error) {\n logger.error('Token refresh failed', { error })\n await storage.clear()\n onRefreshFailed?.()\n return null\n }\n }\n\n return {\n storage,\n refresh,\n\n async setTokens(tokens: TokenPair) {\n await storage.setAccessToken(tokens.accessToken)\n await storage.setRefreshToken(tokens.refreshToken)\n },\n\n async clear() {\n await storage.clear()\n },\n\n onTokenRefreshed(callback: RefreshCallback): () => void {\n callbacks.push(callback)\n return () => {\n const idx = callbacks.indexOf(callback)\n if (idx >= 0)\n callbacks.splice(idx, 1)\n }\n },\n }\n}\n\n/** Token 管理器类型 */\nexport type TokenManager = ReturnType<typeof createTokenManager>\n","/**\n * @h-ai/api-client — 模块入口\n *\n * 提供统一的 `api` 对象,管理 HTTP 客户端运行时状态与生命周期。\n * @module api-client-main\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ApiClient, ApiClientConfig, ApiClientFunctions, TokenPair } from './api-client-types.js'\n\nimport { core, err, ok } from '@h-ai/core'\nimport { createLocalStorageTokenStorage } from './api-client-auth.js'\nimport { createContractCaller } from './api-client-contract.js'\nimport { createFetchClient } from './api-client-fetch.js'\nimport { apiClientM } from './api-client-i18n.js'\nimport { createTokenManager } from './api-client-token-manager.js'\nimport { HaiApiClientError } from './api-client-types.js'\n\nconst logger = core.logger.child({ module: 'api-client', scope: 'main' })\nconst TRAILING_SLASHES_REGEX = /\\/+$/\n\n// ─── 内部状态 ───\n\n/** 当前 ApiClient 实例(init 后非空,close 后置空) */\nlet currentClient: ApiClient | null = null\n\n/** 当前客户端配置(init 后非空,close 后置空) */\nlet currentConfig: ApiClientConfig | null = null\n\n/** 并发初始化防护标志 */\nlet initInProgress = false\n\n// ─── 内部工厂 ───\n\n/**\n * 根据配置创建 ApiClient 实例\n *\n * 仅供 init() 内部使用,不对外暴露。\n */\nfunction createClient(config: ApiClientConfig): ApiClient {\n // 优先使用外部传入的 fetch(便于测试/跨平台注入);未传入时回退到全局 fetch\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis)\n // auth 开启时,默认使用 localStorage 作为 Token 存储\n const tokenStorage = config.auth?.storage ?? createLocalStorageTokenStorage()\n\n // Token 管理器(可选)\n const tokenManager = config.auth\n ? createTokenManager(\n tokenStorage,\n `${config.baseUrl.replace(TRAILING_SLASHES_REGEX, '')}${config.auth.refreshUrl}`,\n fetchFn,\n config.auth.onRefreshFailed,\n )\n : undefined\n\n // 注册外部回调\n if (config.auth?.onTokenRefreshed && tokenManager) {\n tokenManager.onTokenRefreshed(config.auth.onTokenRefreshed)\n }\n\n // Fetch Client\n const fetchClient = createFetchClient(config, tokenManager)\n\n // 契约调用\n const call = createContractCaller(fetchClient)\n\n // Auth 管理接口\n const auth: ApiClient['auth'] = {\n async setTokens(tokens: TokenPair) {\n if (tokenManager) {\n await tokenManager.setTokens(tokens)\n }\n },\n async clear() {\n if (tokenManager) {\n await tokenManager.clear()\n }\n },\n onTokenRefreshed(callback: (tokens: TokenPair) => void): () => void {\n if (tokenManager) {\n return tokenManager.onTokenRefreshed(callback)\n }\n return () => { }\n },\n }\n\n return {\n get: fetchClient.get,\n post: fetchClient.post,\n put: fetchClient.put,\n patch: fetchClient.patch,\n delete: fetchClient.delete,\n upload: fetchClient.upload,\n stream: fetchClient.stream,\n call,\n auth,\n }\n}\n\n// ─── 未初始化占位 ───\n\n/**\n * 未初始化状态的错误工具包\n *\n * 当 api 未调用 init() 就直接使用 HTTP 方法时,\n * 所有方法调用都会返回 NOT_INITIALIZED 错误。\n */\nconst notInitialized = core.module.createNotInitializedKit(\n HaiApiClientError.NOT_INITIALIZED,\n () => apiClientM('apiClient_notInitialized'),\n)\n\n/** 未初始化时的 HTTP 操作占位代理(get/post/put/patch/delete/upload/call) */\nconst notInitializedOps = notInitialized.proxy<Pick<ApiClient, 'get' | 'post' | 'put' | 'patch' | 'delete' | 'upload' | 'call'>>()\n\n/** 未初始化时的 Token 管理占位 */\nconst notInitializedAuth: ApiClient['auth'] = {\n async setTokens() {\n logger.warn('api.auth.setTokens called before initialization, ignored')\n },\n async clear() {\n logger.warn('api.auth.clear called before initialization, ignored')\n },\n onTokenRefreshed() {\n logger.warn('api.auth.onTokenRefreshed called before initialization, ignored')\n return () => { }\n },\n}\n\n/**\n * 未初始化时的流式请求占位\n *\n * async generator 无法返回 HaiResult,迭代时抛出异常。\n */\nfunction notInitializedStreamFn(_path: string, _body?: unknown, _options?: { signal?: AbortSignal }): AsyncIterable<string> {\n return {\n [Symbol.asyncIterator]() {\n return {\n async next(): Promise<IteratorResult<string>> {\n throw new Error(apiClientM('apiClient_notInitialized'))\n },\n }\n },\n }\n}\n\n// ─── API 客户端单例 ───\n\n/**\n * API 客户端单例\n *\n * 使用前必须先调用 `api.init()` 初始化,传入 baseUrl 等配置信息。\n * 初始化后通过 `api.get`、`api.post`、`api.call` 等方法发起请求。\n *\n * @example\n * ```ts\n * import { api } from '@h-ai/api-client'\n *\n * // 初始化\n * await api.init({\n * baseUrl: 'https://api.example.com/api/v1',\n * auth: { refreshUrl: '/auth/refresh' },\n * })\n *\n * // 契约调用\n * const result = await api.call(loginEndpoint, { identifier: 'alice', password: 'xxx' })\n *\n * // 通用 HTTP\n * const users = await api.get<User[]>('/users', { page: 1 })\n *\n * // 关闭\n * await api.close()\n * ```\n */\nexport const api: ApiClientFunctions = {\n /**\n * 初始化 API 客户端\n *\n * 如果当前已有活跃实例,会先自动 close 再重新初始化。\n * 创建异常时返回 CONFIG_ERROR 错误。\n *\n * @param config 客户端配置(baseUrl、auth 等)\n * @returns 成功时返回 ok(undefined);失败时返回包含错误码和消息的 err。\n */\n async init(config: ApiClientConfig): Promise<HaiResult<void>> {\n if (initInProgress) {\n return err(\n HaiApiClientError.CONFIG_ERROR,\n apiClientM('apiClient_configError', { params: { error: 'initialization already in progress' } }),\n )\n }\n\n initInProgress = true\n try {\n if (currentClient) {\n logger.warn('Api-client module is already initialized, reinitializing')\n await api.close()\n }\n\n logger.info('Initializing api-client module')\n\n currentClient = createClient(config)\n currentConfig = config\n logger.info('Api-client module initialized')\n return ok(undefined)\n }\n catch (error) {\n logger.error('Api-client module initialization failed', { error })\n return err(\n HaiApiClientError.CONFIG_ERROR,\n apiClientM('apiClient_configError', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n finally {\n initInProgress = false\n }\n },\n\n /** GET 请求。未初始化时返回 NOT_INITIALIZED 错误 */\n get get() { return currentClient?.get ?? notInitializedOps.get },\n /** POST 请求。未初始化时返回 NOT_INITIALIZED 错误 */\n get post() { return currentClient?.post ?? notInitializedOps.post },\n /** PUT 请求。未初始化时返回 NOT_INITIALIZED 错误 */\n get put() { return currentClient?.put ?? notInitializedOps.put },\n /** PATCH 请求。未初始化时返回 NOT_INITIALIZED 错误 */\n get patch() { return currentClient?.patch ?? notInitializedOps.patch },\n /** DELETE 请求。未初始化时返回 NOT_INITIALIZED 错误 */\n get delete() { return currentClient?.delete ?? notInitializedOps.delete },\n /** 文件上传。未初始化时返回 NOT_INITIALIZED 错误 */\n get upload() { return currentClient?.upload ?? notInitializedOps.upload },\n /** 契约调用。未初始化时返回 NOT_INITIALIZED 错误 */\n get call() { return currentClient?.call ?? notInitializedOps.call },\n\n /**\n * 流式请求。未初始化时迭代抛出异常。\n *\n * @throws 未初始化时抛出 Error\n */\n get stream() { return currentClient?.stream ?? notInitializedStreamFn },\n\n /** Token 管理接口。未初始化时为空操作 */\n get auth() { return currentClient?.auth ?? notInitializedAuth },\n\n /** 当前客户端配置;未初始化或已关闭时为 null */\n get config() { return currentConfig },\n\n /** 是否已完成初始化 */\n get isInitialized() { return currentClient !== null },\n\n /**\n * 关闭 API 客户端并释放资源\n *\n * 关闭后所有 HTTP 操作将返回 NOT_INITIALIZED 错误。\n * 重复调用不会报错。\n */\n async close() {\n if (!currentClient) {\n currentConfig = null\n return\n }\n\n logger.info('Closing api-client module')\n\n currentClient = null\n currentConfig = null\n\n logger.info('Api-client module closed')\n },\n}\n"]}
1
+ {"version":3,"sources":["../src/api-client-auth.ts","../messages/en-US.json","../messages/zh-CN.json","../src/api-client-i18n.ts","../src/api-client-types.ts","../src/api-client-main.ts"],"names":["core"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @h-ai/api-client — Token 存储与刷新管理\n *\n * 提供两个内置 Token 存储适配器(localStorage / 内存)和一个 Token 管理器\n * (封装存储读写、自动刷新、并发去重、回调通知)。\n *\n * @example 浏览器 SPA\n * ```ts\n * import { apiClient } from '@h-ai/api-client'\n *\n * await apiClient.init({\n * baseUrl: 'https://api.example.com/api/v1',\n * auth: { storage: apiClient.tokenStorage.localStorage() },\n * })\n * ```\n *\n * @example Node.js 测试\n * ```ts\n * import { apiClient } from '@h-ai/api-client'\n *\n * const storage = apiClient.tokenStorage.memory()\n * await storage.setAccessToken('abc')\n * ```\n *\n * @module api-client-auth\n */\n\nimport type { TokenPair, TokenStorage } from './api-client-types.js'\nimport { core } from '@h-ai/core'\nimport { z } from 'zod'\n\nconst logger = core.logger.child({ module: 'api-client', scope: 'auth' })\n\n/**\n * httpOnly cookie 模式哨兵值。\n * `apiClient.tokenStorage.httpOnlyCookie()` 的 `getRefreshToken()` 返回此值,\n * 告知 `doRefresh` 应依赖浏览器自动发送的 httpOnly Cookie,\n * 而不是将 refreshToken 写入请求体。\n */\nconst HTTPONLY_COOKIE_SENTINEL = '__httponly_cookie__'\n\n// ─── localStorage 存储 ────────────────────────────────────────────────────────\n\nconst LS_ACCESS_KEY = 'hai_access_token'\nconst LS_REFRESH_KEY = 'hai_refresh_token'\n\n/**\n * 创建基于 `localStorage` 的 Token 存储(浏览器 SPA / PWA)。\n *\n * ⚠️ 安全提示(XSS 风险):\n * - `localStorage` 对同源脚本可读,任意 XSS 漏洞都可以偷取 Token。\n * - 生产环境应优先使用 httpOnly cookie + SameSite 或 BFF 主机代理。\n * - 本适配器仅适用于内部工具、Demo、或者已接受 XSS 风险的浏览器场景,\n * 并且在调用方明确选择使用。`apiClient.create` 默认不会使用本适配器,\n * 需调用方显式传入 `auth.storage = apiClient.tokenStorage.localStorage()`。\n *\n * @example\n * ```ts\n * await apiClient.init({\n * baseUrl: 'https://api.example.com/api/v1',\n * auth: { storage: apiClient.tokenStorage.localStorage() },\n * })\n * ```\n */\nexport function createLocalStorageTokenStorage(): TokenStorage {\n // 首次实例化时警告一次,提示调用方可能需要重新评估安全模型。\n logger.warn('apiClient.tokenStorage.localStorage: storing tokens in localStorage exposes them to XSS. Prefer httpOnly cookies for production.')\n return {\n async getAccessToken() {\n return globalThis.localStorage?.getItem(LS_ACCESS_KEY) ?? null\n },\n async setAccessToken(token) {\n globalThis.localStorage?.setItem(LS_ACCESS_KEY, token)\n },\n async getRefreshToken() {\n return globalThis.localStorage?.getItem(LS_REFRESH_KEY) ?? null\n },\n async setRefreshToken(token) {\n globalThis.localStorage?.setItem(LS_REFRESH_KEY, token)\n },\n async clear() {\n globalThis.localStorage?.removeItem(LS_ACCESS_KEY)\n globalThis.localStorage?.removeItem(LS_REFRESH_KEY)\n },\n }\n}\n\n// ─── 内存存储 ─────────────────────────────────────────────────────────────────\n\n/**\n * 创建内存 Token 存储(Node.js 测试 / SSR / 短生命周期场景)。\n * 页面刷新后丢失。\n *\n * @example\n * ```ts\n * const storage = apiClient.tokenStorage.memory()\n * await storage.setAccessToken('abc')\n * ```\n */\nexport function createMemoryTokenStorage(): TokenStorage {\n let accessToken: string | null = null\n let refreshToken: string | null = null\n return {\n async getAccessToken() { return accessToken },\n async setAccessToken(token) { accessToken = token },\n async getRefreshToken() { return refreshToken },\n async setRefreshToken(token) { refreshToken = token },\n async clear() {\n accessToken = null\n refreshToken = null\n },\n }\n}\n\n// ─── httpOnly Cookie 存储 ────────────────────────────────────────────────────\n\n/**\n * 创建基于 httpOnly cookie 的 Token 存储(生产环境推荐方案)。\n *\n * **安全模型:**\n * - `accessToken` 保存在**内存**中:JS 可读写,用于注入 `Authorization: Bearer`;\n * 页面刷新后丢失,由 refresh 流程自动补充。\n * - `refreshToken` 保存在服务端设置的 **httpOnly cookie** 中:\n * - JS 不可读写,XSS 脚本无法直接盗取。\n * - 结合 `SameSite=Strict` 可阻止 CSRF 攻击。\n * - 浏览器在每次请求时自动携带,无需客户端显式传递。\n *\n * **服务端配套要求:**\n * 1. 登录端点在响应中设置:\n * ```\n * Set-Cookie: refresh_token=<token>; HttpOnly; SameSite=Strict; Secure;\n * Path=/api/v1/auth/refresh; Max-Age=<seconds>\n * ```\n * `Path` 限定为 refresh 端点,减少 Cookie 暴露面。\n * 2. Refresh 端点从 Cookie 读取 refresh token(忽略请求体中的 `refreshToken` 字段)。\n * 3. Logout 端点清除 Cookie:\n * ```\n * Set-Cookie: refresh_token=; HttpOnly; SameSite=Strict; Secure;\n * Path=/api/v1/auth/refresh; Max-Age=0\n * ```\n *\n * **跨域注意事项:**\n * 若 API 与前端不同源,服务端还需设置:\n * `Access-Control-Allow-Origin: <前端域名>` 和 `Access-Control-Allow-Credentials: true`。\n * 调用方不需要做额外配置,`apiClient.create` 会自动识别并设置 `credentials: 'include'`。\n *\n * @example\n * ```ts\n * await apiClient.init({\n * baseUrl: 'https://api.example.com/api/v1',\n * auth: { storage: apiClient.tokenStorage.httpOnlyCookie() },\n * })\n * ```\n */\nexport function createHttpOnlyCookieTokenStorage(): TokenStorage {\n // access token 保存在内存中,用于注入 Authorization 请求头\n let memoryAccessToken: string | null = null\n return {\n async getAccessToken() { return memoryAccessToken },\n async setAccessToken(token) { memoryAccessToken = token },\n // refresh token 由服务端通过 Set-Cookie 设置为 httpOnly cookie;\n // JS 不可见,返回哨兵值让 TokenManager 识别此模式。\n async getRefreshToken() { return HTTPONLY_COOKIE_SENTINEL },\n // refresh token 由服务端管理,JS 端无法写入 httpOnly cookie,忽略此调用。\n async setRefreshToken(_token) { /* 由服务端 Set-Cookie 响应头管理,客户端无需操作 */ },\n async clear() {\n memoryAccessToken = null\n // httpOnly cookie 的清除必须由服务端 logout 端点完成(Set-Cookie: Max-Age=0);\n // 客户端无法通过 JS 直接删除 httpOnly cookie。\n },\n }\n}\n\n// ─── Token 管理器 ─────────────────────────────────────────────────────────────\n\n/** 校验 refresh 响应体中的 Token 字段;httpOnly cookie 模式允许不返回 refreshToken。 */\nconst RefreshTokenPayloadSchema = z.object({\n accessToken: z.string().min(1),\n refreshToken: z.string().min(1).optional(),\n expiresIn: z.number().optional(),\n tokenType: z.string().optional(),\n})\n\ntype RefreshCallback = (tokens: TokenPair) => void\n\n/**\n * 创建 Token 管理器:封装存储读写、自动刷新、并发去重与回调通知。\n *\n * 主要供 `apiClient.create` 内部使用,同时作为 named export 暴露给测试与高级用户。\n *\n * 行为约定:\n * - 并发多次 `refresh()` 共享同一个请求。\n * - refresh 接口失败、响应字段缺失或 401,都视为刷新失败:清空存储并触发 `onRefreshFailed`。\n * - 兼容两种响应格式:`{ data: tokens }` 与 `{ data: { tokens } }`(HaiResult 包装)。\n *\n * @example\n * ```ts\n * const manager = createTokenManager(\n * apiClient.tokenStorage.memory(),\n * 'https://api.example.com/api/v1/auth/refresh',\n * fetch,\n * () => notifyLoginRequired(),\n * )\n *\n * const off = manager.onTokenRefreshed(tokens => syncTokens(tokens))\n * const tokens = await manager.refresh()\n * off()\n * ```\n *\n * @param storage - Token 存储适配器\n * @param refreshEndpointUrl - refresh 接口完整 URL(`baseUrl + refreshPath`)\n * @param fetchFn - fetch 实现(允许注入 mock)\n * @param onRefreshFailed - 刷新失败回调\n * @param refreshTimeoutMs - 刷新请求超时(ms),默认 10_000\n * @returns Token 管理器实例\n */\nexport function createTokenManager(\n storage: TokenStorage,\n refreshEndpointUrl: string,\n fetchFn: typeof globalThis.fetch,\n onRefreshFailed?: () => void,\n refreshTimeoutMs: number = 10_000,\n) {\n const callbacks: RefreshCallback[] = []\n let refreshPromise: Promise<TokenPair | null> | null = null\n\n async function refresh(): Promise<TokenPair | null> {\n // 并发去重:同一时刻只发一次 refresh,其它调用复用同一个 Promise\n if (refreshPromise)\n return refreshPromise\n refreshPromise = doRefresh()\n try {\n return await refreshPromise\n }\n finally {\n refreshPromise = null\n }\n }\n\n async function doRefresh(): Promise<TokenPair | null> {\n const refreshToken = await storage.getRefreshToken()\n if (!refreshToken) {\n logger.warn('Token refresh skipped, no refresh token available')\n onRefreshFailed?.()\n return null\n }\n\n logger.debug('Refreshing token')\n // 超时保护:避免 refresh 接口挂死时 dedup Promise 永不 resolve,连带所有等待者 hang。\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), refreshTimeoutMs)\n try {\n // httpOnly cookie 模式:浏览器自动发送 Cookie,请求体无需携带 refreshToken;\n // 同时设置 credentials:'include' 以支持跨域 Cookie 发送。\n const useHttpOnlyCookie = refreshToken === HTTPONLY_COOKIE_SENTINEL\n const requestInit: RequestInit = {\n method: 'POST',\n body: useHttpOnlyCookie ? undefined : JSON.stringify({ refreshToken }),\n credentials: useHttpOnlyCookie ? 'include' : 'same-origin',\n signal: controller.signal,\n }\n if (!useHttpOnlyCookie) {\n requestInit.headers = { 'Content-Type': 'application/json' }\n }\n const response = await fetchFn(refreshEndpointUrl, requestInit)\n\n if (!response.ok) {\n // 仅在服务端明确返回 401/4xx 时才清除 Token(refresh token 已失效);\n // 5xx 作为服务端临时故障,保留 Token 让下一次请求重试。\n if (response.status >= 400 && response.status < 500) {\n await storage.clear()\n onRefreshFailed?.()\n }\n else {\n logger.warn('Token refresh transient failure, keeping tokens', { status: response.status })\n }\n return null\n }\n\n const body = await response.json() as { data?: unknown }\n const parsed = RefreshTokenPayloadSchema.safeParse(readTokenPayload(body.data))\n if (!parsed.success) {\n logger.warn('Token refresh returned invalid data', { issues: parsed.error.issues })\n await storage.clear()\n onRefreshFailed?.()\n return null\n }\n if (!useHttpOnlyCookie && !parsed.data.refreshToken) {\n logger.warn('Token refresh returned invalid data', { issues: [{ path: ['refreshToken'], message: 'Required' }] })\n await storage.clear()\n onRefreshFailed?.()\n return null\n }\n\n // 默认值兜底,避免不安全强转\n const refreshTokenForStorage = parsed.data.refreshToken ?? HTTPONLY_COOKIE_SENTINEL\n const tokens: TokenPair = {\n accessToken: parsed.data.accessToken,\n refreshToken: refreshTokenForStorage,\n expiresIn: parsed.data.expiresIn ?? 3600,\n tokenType: 'Bearer',\n }\n await storage.setAccessToken(tokens.accessToken)\n await storage.setRefreshToken(refreshTokenForStorage)\n logger.info('Token refreshed successfully')\n for (const cb of callbacks) cb(tokens)\n return tokens\n }\n catch (error) {\n // 网络或 fetch 本身抛异常(超时、断网、CORS)视为可重试的暂时性错误,\n // 不清除 Token,仅记录日志。调用方可在下次请求时重试。\n logger.error('Token refresh failed (transient)', { error })\n return null\n }\n finally {\n clearTimeout(timeoutId)\n }\n }\n\n return {\n storage,\n refresh,\n async setTokens(tokens: TokenPair) {\n await storage.setAccessToken(tokens.accessToken)\n if (tokens.refreshToken)\n await storage.setRefreshToken(tokens.refreshToken)\n },\n async clear() {\n await storage.clear()\n },\n onTokenRefreshed(callback: RefreshCallback): () => void {\n callbacks.push(callback)\n return () => {\n const idx = callbacks.indexOf(callback)\n if (idx >= 0)\n callbacks.splice(idx, 1)\n }\n },\n }\n}\n\n/** Token 管理器类型(`createTokenManager` 返回值)。 */\nexport type TokenManager = ReturnType<typeof createTokenManager>\n\n/** 兼容 `{ data: tokens }` 与 `{ data: { tokens } }` 两种 refresh 响应体。 */\nfunction readTokenPayload(data: unknown): unknown {\n if (typeof data === 'object' && data !== null && 'tokens' in data) {\n return (data as { tokens: unknown }).tokens\n }\n return data\n}\n","{\n \"apiClient_networkError\": \"Network request failed\",\n \"apiClient_timeout\": \"Request timeout\",\n \"apiClient_serverError\": \"Server error ({status})\",\n \"apiClient_unauthorized\": \"Unauthorized, please log in again\",\n \"apiClient_forbidden\": \"Access forbidden\",\n \"apiClient_notFound\": \"Resource not found\",\n \"apiClient_validationFailed\": \"Request validation failed\",\n \"apiClient_tokenRefreshFailed\": \"Token refresh failed, please log in again\",\n \"apiClient_notInitialized\": \"API client not initialized, please call api.init() first\",\n \"apiClient_configError\": \"API client config error: {error}\",\n \"apiClient_responseValidationFailed\": \"Response validation failed\",\n \"apiClient_unknown\": \"Unknown error\"\n}\n","{\n \"apiClient_networkError\": \"网络请求失败\",\n \"apiClient_timeout\": \"请求超时\",\n \"apiClient_serverError\": \"服务器错误({status})\",\n \"apiClient_unauthorized\": \"未授权,请重新登录\",\n \"apiClient_forbidden\": \"无权限访问\",\n \"apiClient_notFound\": \"请求的资源不存在\",\n \"apiClient_validationFailed\": \"请求参数校验失败\",\n \"apiClient_tokenRefreshFailed\": \"Token刷新失败,请重新登录\",\n \"apiClient_notInitialized\": \"API 客户端未初始化,请先调用 api.init()\",\n \"apiClient_configError\": \"API 客户端配置错误:{error}\",\n \"apiClient_responseValidationFailed\": \"响应数据校验失败\",\n \"apiClient_unknown\": \"未知错误\"\n}\n","/**\n * @h-ai/api-client — i18n\n *\n * 模块 i18n 文案访问入口。\n * @module api-client-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\ntype ApiClientMessageKey = keyof typeof messagesZhCN\n\n/**\n * api-client 模块 i18n 文案获取器\n *\n * @param key - 文案 Key\n * @param options - 插值参数\n * @returns 本地化后的文案字符串\n */\nexport const apiClientM = core.i18n.createMessageGetter<ApiClientMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n})\n","/**\n * @h-ai/api-client — 类型与错误码\n *\n * 公共类型(TokenPair、TokenStorage、ApiClientConfig 等)与标准错误集合(HaiApiClientError)。\n * 不包含实现,仅用于跨文件共享与对外导出。\n * @module api-client-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport type { CryptoFunctions } from '@h-ai/crypto'\nimport type { AnyContractRouter, ContractRouterClient } from '@orpc/contract'\nimport type { JsonifiedClient } from '@orpc/openapi-client'\nimport { core } from '@h-ai/core'\n\n// ─── 错误码 ───────────────────────────────────────────────────────────────────\n\nconst ApiClientErrorInfo = {\n NETWORK_ERROR: '001:502',\n TIMEOUT: '002:504',\n SERVER_ERROR: '003:502',\n UNAUTHORIZED: '004:401',\n FORBIDDEN: '005:403',\n NOT_FOUND: '006:404',\n VALIDATION_FAILED: '007:400',\n TOKEN_REFRESH_FAILED: '008:401',\n NOT_INITIALIZED: '010:500',\n CONFIG_ERROR: '011:500',\n UNKNOWN: '099:500',\n} as const satisfies ErrorInfo\n\n/**\n * API client 标准错误集合(遵循 `@h-ai/core` 错误码规范)。\n *\n * @example\n * ```ts\n * if (!result.success && result.error.code === HaiApiClientError.UNAUTHORIZED.code) {\n * redirectToLogin()\n * }\n * ```\n */\nexport const HaiApiClientError = core.error.buildHaiErrorsDef('api-client', ApiClientErrorInfo)\n\n// ─── Token ────────────────────────────────────────────────────────────────────\n\n/** Token 对(与 `@h-ai/iam` 的 TokenPair 对齐)。 */\nexport interface TokenPair {\n /** 短期访问凭证,请求时作为 `Authorization: Bearer ...`。 */\n readonly accessToken: string\n /** 长期刷新凭证;httpOnly cookie 模式下由服务端管理,响应体中可能不存在。 */\n readonly refreshToken?: string\n /** accessToken 有效期秒数。 */\n readonly expiresIn: number\n /** 固定为 `'Bearer'`。 */\n readonly tokenType: 'Bearer'\n}\n\n/**\n * Token 存储适配器。\n *\n * 内置实现:\n * - `apiClient.tokenStorage.httpOnlyCookie()` — **默认**;浏览器端推荐,refresh token 由服务端管理,防 XSS。\n * - `apiClient.tokenStorage.memory()` — Node.js 测试 / SSR(需显式传入)。\n * - `apiClient.tokenStorage.localStorage()` — 浏览器 SPA / PWA(有 XSS 风险,生产不推荐)。\n *\n * Capacitor / 小程序场景请由对应模块提供(例如 `@h-ai/capacitor`)。\n */\nexport interface TokenStorage {\n readonly getAccessToken: () => Promise<string | null>\n readonly setAccessToken: (token: string) => Promise<void>\n readonly getRefreshToken: () => Promise<string | null>\n readonly setRefreshToken: (token: string) => Promise<void>\n readonly clear: () => Promise<void>\n}\n\n// ─── 配置 ─────────────────────────────────────────────────────────────────────\n\n/** Token 自动刷新配置。 */\nexport interface AuthConfig {\n /**\n * Token 存储适配器;默认 `apiClient.tokenStorage.httpOnlyCookie()`(refresh token 由服务端管理,防 XSS)。\n *\n * - SSR / Node.js 测试场景请显式传入 `apiClient.tokenStorage.memory()`。\n * - 浏览器 SPA 如确需持久化,可显式传 `apiClient.tokenStorage.localStorage()`,\n * 但请先评估 XSS 风险。\n * - Capacitor / 小程序请使用对应平台的安全存储适配器(如 `@h-ai/capacitor`)。\n */\n readonly storage?: TokenStorage\n /** 刷新接口路径,相对于 `baseUrl`,默认 `/auth/refresh`。 */\n readonly refreshPath?: string\n /**\n * 刷新请求超时(ms),默认 10_000。\n * 避免 refresh 接口上游挂死时所有 dedup 调用方一起 hang。\n * 超时后按现有 transient 失败处理(不清 token,下次请求可重试)。\n */\n readonly refreshTimeoutMs?: number\n /** 刷新成功回调,用于同步状态(例如多 Tab 广播)。 */\n readonly onTokenRefreshed?: (tokens: TokenPair) => void\n /** 刷新失败回调(如 refresh token 已失效),通常用于跳转登录页。 */\n readonly onRefreshFailed?: () => void\n}\n\n/** API client 初始化配置。 */\nexport interface ApiClientConfig {\n /** API service 完整 baseUrl,通常含 `apiPrefix`,例如 `https://api.example.com/api/v1`。 */\n readonly baseUrl: string\n /** 认证配置;不传则不启用 Token 注入与自动刷新。 */\n readonly auth?: AuthConfig\n /** 请求超时(ms),默认 30000。 */\n readonly timeout?: number\n /** 客户端标识,写入 `x-request-client` 请求头,默认 `hai-api-client`。 */\n readonly clientName?: string\n /** 额外请求头,可为静态对象或异步函数。 */\n readonly headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>)\n /** 自定义 fetch(测试 mock / Capacitor / 小程序桥接)。 */\n readonly fetch?: typeof globalThis.fetch\n /**\n * 启用端到端传输加密(opt-in)。\n *\n * 配置后所有出站请求会在底层 fetch 之上做一次混合加密,并自动解密\n * 标记为 `X-Encrypted: true` 的响应。服务端需启用对应的 `serv.createApp({ transport })`。\n *\n * `crypto` 字段结构与 `@h-ai/crypto` 的 `crypto` 实例兼容;通常直接传入:\n *\n * @example\n * ```ts\n * import { apiClient } from '@h-ai/api-client'\n * import { crypto } from '@h-ai/crypto'\n *\n * await crypto.init()\n * await apiClient.init({\n * baseUrl: 'https://api.example.com/api/v1',\n * transport: { crypto },\n * })\n * ```\n */\n readonly transport?: ApiClientTransportConfig\n}\n\n// ─── 传输加密 ────────────────────────────────────────────────────────────────\n\n/** {@link ApiClientConfig.transport} 的配置项。 */\nexport interface ApiClientTransportConfig {\n /**\n * crypto 服务实例(通常直接传入 `@h-ai/crypto` 的 `crypto`)。\n * api-client 通过 `crypto.transport.createClient(...)` 创建会话。\n */\n readonly crypto: CryptoFunctions\n /**\n * 密钥协商端点路径,相对于 `baseUrl`,默认 `/_hai/key-exchange`。\n *\n * 必须与服务端 `serv.createApp({ transport: { keyExchangePath } })` 一致。\n */\n readonly keyExchangePath?: string\n}\n\n// ─── Client 接口 ──────────────────────────────────────────────────────────────\n\n/** Token 辅助操作。 */\nexport interface ApiClientAuth {\n /** 手动写入 Token(例如登录成功后)。 */\n readonly setTokens: (tokens: TokenPair) => Promise<void>\n /** 清空存储的 Token(登出)。 */\n readonly clear: () => Promise<void>\n /** 订阅 Token 刷新成功事件,返回取消订阅函数。 */\n readonly onTokenRefreshed: (callback: (tokens: TokenPair) => void) => () => void\n}\n\n/** API client 生命周期能力。 */\nexport interface ApiClientLifecycle {\n /**\n * 初始化 client;必须在调用任何 procedure 前完成。\n *\n * @example\n * ```ts\n * await client.init({\n * baseUrl: 'https://api.example.com/api/v1',\n * auth: { refreshPath: '/auth/refresh' },\n * timeout: 15_000,\n * })\n * ```\n */\n readonly init: (config: ApiClientConfig) => Promise<HaiResult<void>>\n /** 释放资源并允许重新 `init`。 */\n readonly close: () => Promise<void>\n /** 当前运行配置;未初始化时为 `null`。 */\n readonly config: ApiClientConfig | null\n /** 是否已完成初始化。 */\n readonly isInitialized: boolean\n /** Token 辅助操作。 */\n readonly auth: ApiClientAuth\n}\n\n/** 根据 oRPC contract 推导出的 typed API client(生命周期 + procedure 调用)。 */\nexport type ApiClient<TContract extends AnyContractRouter>\n = ApiClientLifecycle & JsonifiedClient<ContractRouterClient<TContract>>\n","/**\n * @h-ai/api-client — 主实现\n *\n * 包含两部分:\n * - `createApiClient(contract)`:根据 oRPC contract 创建 typed client 工厂(内部实现)。\n * - `apiClient`:统一公开入口;自身就是默认单例,同时挂载 `create` / `tokenStorage`。\n *\n * Client 同时具备生命周期能力(init/close/config/isInitialized/auth)和 contract\n * 推导出的 procedure 嵌套调用能力(如 `client.iam.auth.login(input)`)。\n *\n * 内置能力:\n * - 401 自动 refresh + 单次重试\n * - 并发 refresh 共享 Promise\n * - 请求超时(AbortController)\n * - `ORPCError` → `HaiApiClientError` 标准化映射\n * - 未初始化时调用 procedure 返回 `NOT_INITIALIZED`,不抛异常\n *\n * @example 默认单例\n * ```ts\n * import { apiClient } from '@h-ai/api-client'\n *\n * await apiClient.init({ baseUrl: 'https://api.example.com/api/v1' })\n * const me = await apiClient.iam.auth.currentUser()\n * await apiClient.close()\n * ```\n *\n * @example 自定义 contract\n * ```ts\n * import { apiClient } from '@h-ai/api-client'\n * import { apiContract } from '@h-ai/api-contract'\n *\n * const client = apiClient.create(apiContract.create({ iam: apiContract.iam }))\n * await client.init({ baseUrl: 'https://api.example.com/api/v1' })\n * const result = await client.iam.auth.login({ identifier: 'alice', password: 'secret' })\n * ```\n *\n * @module api-client-main\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { TransportClient } from '@h-ai/crypto'\nimport type { AnyContractRouter, ContractRouterClient } from '@orpc/contract'\nimport type { JsonifiedClient } from '@orpc/openapi-client'\nimport type { TokenManager } from './api-client-auth.js'\nimport type {\n ApiClient,\n ApiClientAuth,\n ApiClientConfig,\n ApiClientLifecycle,\n} from './api-client-types.js'\nimport { apiContract, IAM_AUTH_ROUTES } from '@h-ai/api-contract'\nimport { err, ok } from '@h-ai/core'\nimport { createORPCClient, ORPCError } from '@orpc/client'\nimport { OpenAPILink } from '@orpc/openapi-client/fetch'\nimport {\n createHttpOnlyCookieTokenStorage,\n createLocalStorageTokenStorage,\n createMemoryTokenStorage,\n createTokenManager,\n} from './api-client-auth.js'\nimport { apiClientM } from './api-client-i18n.js'\nimport { HaiApiClientError } from './api-client-types.js'\n\nconst DEFAULT_TIMEOUT = 30_000\nconst DEFAULT_CLIENT_NAME = 'hai-api-client'\nconst DEFAULT_REFRESH_PATH = IAM_AUTH_ROUTES.refresh\nconst TRAILING_SLASHES_REGEX = /\\/+$/\n\n/** Token 存储方案集合:内存 / 浏览器 localStorage / httpOnly Cookie。 */\nconst tokenStorage = {\n /** 内存存储——SSR / Node 测试或一次性会话使用。 */\n memory: createMemoryTokenStorage,\n /** 浏览器 `localStorage` 存储——单页应用便捷选项;注意 XSS 风险。 */\n localStorage: createLocalStorageTokenStorage,\n /** httpOnly Cookie 存储——浏览器场景推荐方案。 */\n httpOnlyCookie: createHttpOnlyCookieTokenStorage,\n} as const\n\n// ─── 工厂 ─────────────────────────────────────────────────────────────────────\n\n/**\n * 根据 oRPC contract 创建 typed API client。\n *\n * 返回对象同时具备:\n * - **生命周期能力**:`init` / `close` / `config` / `isInitialized` / `auth`\n * - **contract procedure**:按 contract 嵌套结构调用,例如 `client.iam.auth.login(input)`\n *\n * @example 基础用法\n * ```ts\n * import { apiClient } from '@h-ai/api-client'\n * import { apiContract } from '@h-ai/api-contract'\n *\n * const client = apiClient.create(apiContract.create({ iam: apiContract.iam }))\n * await client.init({ baseUrl: 'https://api.example.com/api/v1' })\n *\n * const result = await client.iam.auth.login({ identifier: 'alice', password: 'secret' })\n * if (result.success) {\n * await client.auth.setTokens(result.data.tokens)\n * }\n *\n * await client.close()\n * ```\n *\n * @example 自定义 fetch / 超时\n * ```ts\n * const client = apiClient.create(contract)\n * await client.init({\n * baseUrl: 'https://api.example.com/api/v1',\n * fetch: customFetch,\n * timeout: 10_000,\n * })\n * ```\n */\nexport function createApiClient<const TContract extends AnyContractRouter>(\n contract: TContract,\n): ApiClient<TContract> {\n // 客户端运行时状态\n const state: {\n config: ApiClientConfig | null\n rawClient: JsonifiedClient<ContractRouterClient<TContract>> | null\n tokenManager: TokenManager | undefined\n transport: TransportClient | undefined\n } = {\n config: null,\n rawClient: null,\n tokenManager: undefined,\n transport: undefined,\n }\n\n const auth: ApiClientAuth = {\n async setTokens(tokens) { await state.tokenManager?.setTokens(tokens) },\n async clear() { await state.tokenManager?.clear() },\n onTokenRefreshed(callback) {\n return state.tokenManager?.onTokenRefreshed(callback) ?? (() => {})\n },\n }\n\n let initPromise: Promise<HaiResult<void>> | null = null\n const lifecycle: ApiClientLifecycle = {\n async init(config) {\n // 并发重入防护:同时多次 init() 只执行一次。\n // 另一个调用方 await 同一个 in-flight Promise,避免重复创建 raw client / token manager。\n if (initPromise)\n return initPromise\n initPromise = (async (): Promise<HaiResult<void>> => {\n try {\n state.config = config\n state.transport = buildTransportSession(config)\n state.tokenManager = buildTokenManager(config, state.transport)\n state.rawClient = buildRawClient(contract, config, state.tokenManager, state.transport)\n return ok(undefined)\n }\n catch (error) {\n return err(\n HaiApiClientError.CONFIG_ERROR,\n apiClientM('apiClient_configError', { params: { error: String(error) } }),\n error,\n )\n }\n })()\n try {\n return await initPromise\n }\n finally {\n initPromise = null\n }\n },\n async close() {\n state.transport?.destroy()\n state.config = null\n state.rawClient = null\n state.tokenManager = undefined\n state.transport = undefined\n },\n get config() { return state.config },\n get isInitialized() { return state.rawClient !== null },\n auth,\n }\n\n /**\n * 顶层 Proxy:把“一个对象同时扮演两种角色”的需求揉到一起。\n *\n * 这个 client 既要像一个普通服务对象,暴露生命周期方法:\n * - `client.init()`\n * - `client.close()`\n * - `client.config`\n * - `client.isInitialized`\n * - `client.auth`\n *\n * 又要像一个按 contract 动态展开的 oRPC client,支持:\n * - `client.iam.auth.login(input)`\n * - `client.storage.object.put(input)`\n * - `client.ai.chat.send(input)`\n *\n * 由于第二类 API 的层级结构是“运行时按属性链逐步访问”的,无法靠写死对象字面量覆盖所有路径,\n * 所以这里使用 Proxy:\n * - 先拦截顶层属性访问;\n * - 如果访问的是生命周期字段,就直接返回 lifecycle 中的真实成员;\n * - 否则把这个属性当成 contract 路径的第一段,继续交给 `createProcedureProxy()` 处理。\n *\n * 换句话说:\n * - `client.init` → 返回 lifecycle.init\n * - `client.auth` → 返回 lifecycle.auth\n * - `client.iam` → 返回一个新的嵌套 Proxy,继续等待 `.auth.login(...)`\n *\n * 注意:如果将来 contract 顶层字段和 lifecycle 字段重名,这里会“优先返回 lifecycle”。\n */\n return new Proxy({}, {\n get(_target, property) {\n // Proxy 的属性键不一定是 string,也可能是 Symbol(例如某些运行时内部探测)。\n // 本 client 只处理字符串路径;非字符串键直接忽略,避免把 Symbol 误当成 API 路径的一部分。\n if (typeof property !== 'string')\n return undefined\n\n // 顶层字段命中 lifecycle 时,直接返回真实成员。\n // 例如:\n // - property === 'init' → 返回 init 函数\n // - property === 'auth' → 返回 auth 对象\n // 这样 `client.init()` / `client.auth.clear()` 就能像普通对象一样工作。\n if (property in lifecycle) {\n return Reflect.get(lifecycle, property)\n }\n\n // 走到这里,说明它不是生命周期字段,那就把它当成 contract 路径的第一段。\n // 例如访问 `client.iam` 时,这里会创建一个 path = ['iam'] 的嵌套 Proxy。\n // 后续如果继续访问 `.auth.login`,path 会逐步变成:\n // ['iam', 'auth'] → ['iam', 'auth', 'login']\n // 最终在函数调用时再映射到真正的 rawClient.iam.auth.login(...args)。\n return createProcedureProxy(state, [property])\n },\n // 这里的返回值在运行时是一个 Proxy,但从“可用能力”上看,它符合 `ApiClient<TContract>`:\n // - 一部分成员来自 lifecycle\n // - 另一部分成员来自 contract 推导出的 procedure 层级\n // 因此使用类型断言把这个动态对象声明为最终对外的 typed client。\n }) as ApiClient<TContract>\n}\n\n// ─── 默认单例 ─────────────────────────────────────────────────────────────────\n\n/**\n * 默认 API typed client:绑定 `iam` / `storage` / `ai` 三个领域。\n *\n * 大多数应用只需 `import { apiClient }` 并调用 `apiClient.init()` 即可。\n *\n * @example\n * ```ts\n * import { apiClient } from '@h-ai/api-client'\n *\n * await apiClient.init({\n * baseUrl: 'http://localhost:3000/api/v1',\n * auth: { refreshPath: '/auth/refresh' },\n * })\n * const result = await apiClient.iam.auth.login({ identifier: 'alice', password: 'secret' })\n * await apiClient.close()\n * ```\n */\nconst defaultApiContract = apiContract.create({ iam: apiContract.iam, storage: apiContract.storage, ai: apiContract.ai })\n\n/** `apiClient` 默认单例 + 工厂命名空间的统一对外类型。 */\nexport type DefaultApiClient = ApiClient<typeof defaultApiContract> & {\n readonly create: typeof createApiClient\n readonly tokenStorage: typeof tokenStorage\n}\n\n/** hai-framework API client 统一入口(默认单例 + `create` + `tokenStorage`)。 */\nexport const apiClient = new Proxy(createApiClient(defaultApiContract) as ApiClient<typeof defaultApiContract>, {\n get(target, property, receiver) {\n if (property === 'create')\n return createApiClient\n if (property === 'tokenStorage')\n return tokenStorage\n return Reflect.get(target as object, property, receiver)\n },\n}) as DefaultApiClient\n\n// ─── 内部:procedure 代理 ─────────────────────────────────────────────────────\n\n/**\n * 构造嵌套 procedure 代理。\n *\n * oRPC client 接口是任意层嵌套的属性 + 末端调用(如 `client.iam.auth.login(input)`)。\n * 这里用统一的 Proxy 透传所有路径,叶子节点(被 apply 时)映射到\n * `state.rawClient[a][b][c](input)` 并把错误标准化为 `HaiResult`。\n */\nfunction createProcedureProxy<TContract extends AnyContractRouter>(\n state: { rawClient: JsonifiedClient<ContractRouterClient<TContract>> | null },\n path: string[],\n): unknown {\n return new Proxy(() => undefined, {\n get(_t, property) {\n if (typeof property !== 'string')\n return undefined\n return createProcedureProxy(state, [...path, property])\n },\n apply(_t, _thisArg, args) {\n return callProcedure(state.rawClient, path, args)\n },\n })\n}\n\nasync function callProcedure(\n rawClient: unknown,\n path: string[],\n args: unknown[],\n): Promise<unknown> {\n if (!rawClient) {\n return err(HaiApiClientError.NOT_INITIALIZED, apiClientM('apiClient_notInitialized'))\n }\n\n // 沿 path 解析 rawClient[a][b][c]...\n let target: unknown = rawClient\n for (const segment of path) {\n if ((typeof target !== 'object' || target === null) && typeof target !== 'function') {\n return err(HaiApiClientError.UNKNOWN, apiClientM('apiClient_unknown'))\n }\n target = Reflect.get(target as object, segment)\n }\n if (typeof target !== 'function') {\n return err(HaiApiClientError.UNKNOWN, apiClientM('apiClient_unknown'))\n }\n\n try {\n return await (target as (...a: unknown[]) => Promise<unknown>)(...args)\n }\n catch (error) {\n return mapClientError(error)\n }\n}\n\n// ─── 内部:构建 raw client 与 token manager ──────────────────────────────────\n\n/** 根据 `auth` 配置决定是否创建 TokenManager。 */\nfunction buildTokenManager(config: ApiClientConfig, transport: TransportClient | undefined): TokenManager | undefined {\n if (!config.auth)\n return undefined\n\n const fetchFn = transport?.encryptedFetch ?? config.fetch ?? globalThis.fetch.bind(globalThis)\n // 默认使用 httpOnly cookie 存储(推荐方案:refresh token 由服务端管理,防 XSS)。\n // SSR / Node.js 测试场景请显式传入 `apiClient.tokenStorage.memory()`。\n // 浏览器 localStorage 场景请显式传入 `apiClient.tokenStorage.localStorage()`(有 XSS 风险)。\n const storage = config.auth.storage ?? createHttpOnlyCookieTokenStorage()\n const baseUrl = config.baseUrl.replace(TRAILING_SLASHES_REGEX, '')\n const refreshPath = config.auth.refreshPath ?? DEFAULT_REFRESH_PATH\n const refreshUrl = `${baseUrl}${refreshPath.startsWith('/') ? refreshPath : `/${refreshPath}`}`\n\n const manager = createTokenManager(storage, refreshUrl, fetchFn, config.auth.onRefreshFailed, config.auth.refreshTimeoutMs)\n if (config.auth.onTokenRefreshed) {\n manager.onTokenRefreshed(config.auth.onTokenRefreshed)\n }\n return manager\n}\n\n/** 根据 `transport` 配置创建传输加密会话。 */\nfunction buildTransportSession(config: ApiClientConfig): TransportClient | undefined {\n if (!config.transport)\n return undefined\n const baseFetch = config.fetch ?? globalThis.fetch.bind(globalThis)\n const baseUrl = config.baseUrl.replace(TRAILING_SLASHES_REGEX, '')\n const path = config.transport.keyExchangePath ?? '/_hai/key-exchange'\n const keyExchangeUrl = `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`\n return config.transport.crypto.transport.createClient({ keyExchangeUrl, fetch: baseFetch })\n}\n\n/** 构造 oRPC OpenAPILink + raw client。 */\nfunction buildRawClient<TContract extends AnyContractRouter>(\n contract: TContract,\n config: ApiClientConfig,\n tokenManager: TokenManager | undefined,\n transport: TransportClient | undefined,\n): JsonifiedClient<ContractRouterClient<TContract>> {\n const link = new OpenAPILink(contract, {\n url: config.baseUrl,\n headers: async () => buildHeaders(config, tokenManager),\n fetch: async (request, init) => fetchWithRefresh(request, init, config, tokenManager, transport),\n })\n return createORPCClient<JsonifiedClient<ContractRouterClient<TContract>>>(link)\n}\n\n/** 组装请求头:用户配置 + 客户端标识 + Bearer Token。 */\nasync function buildHeaders(\n config: ApiClientConfig,\n tokenManager: TokenManager | undefined,\n): Promise<Record<string, string>> {\n const configured = typeof config.headers === 'function' ? await config.headers() : config.headers ?? {}\n const accessToken = await tokenManager?.storage.getAccessToken()\n return {\n ...configured,\n 'x-request-client': config.clientName ?? DEFAULT_CLIENT_NAME,\n ...(accessToken ? { authorization: `Bearer ${accessToken}` } : {}),\n }\n}\n\n/** 401 自动 refresh 并重试一次。 */\nasync function fetchWithRefresh(\n request: Request,\n init: { redirect?: Request['redirect'] },\n config: ApiClientConfig,\n tokenManager: TokenManager | undefined,\n transport: TransportClient | undefined,\n): Promise<Response> {\n // Fetch Request 的 body 是一次性可读流;为了支持 401 后重发 POST/PUT 等带 body 的请求,\n // 必须在首次发送前 `clone()` 一份。即使没有 401,clone 后的副本也只会被 GC 回收,无副作用。\n const retryRequest = tokenManager ? request.clone() : undefined\n const response = await fetchWithTimeout(request, init, config, transport)\n if (response.status !== 401 || !tokenManager || !retryRequest)\n return response\n\n const tokens = await tokenManager.refresh()\n if (!tokens)\n return response\n\n const headers = new Headers(retryRequest.headers)\n headers.set('authorization', `Bearer ${tokens.accessToken}`)\n return fetchWithTimeout(new Request(retryRequest, { headers }), init, config, transport)\n}\n\n/** fetch + AbortController 超时控制(联动调用方原始 signal)。 */\nasync function fetchWithTimeout(\n request: Request,\n init: { redirect?: Request['redirect'] },\n config: ApiClientConfig,\n transport: TransportClient | undefined,\n): Promise<Response> {\n // 启用传输加密时,用 encryptedFetch 作为实际 fetch;\n // 它会首次请求前自动完成密钥协商,后续请求复用会话。\n const fetchFn = transport?.encryptedFetch ?? config.fetch ?? globalThis.fetch.bind(globalThis)\n const timeout = config.timeout ?? DEFAULT_TIMEOUT\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n // 保留调用方原始 signal 的中断能力:上游主动 abort 也能控制超时 controller。\n const userSignal = request.signal\n if (userSignal) {\n if (userSignal.aborted) {\n controller.abort()\n }\n else {\n userSignal.addEventListener('abort', () => controller.abort(), { once: true })\n }\n }\n try {\n return await fetchFn(new Request(request, { signal: controller.signal }), init)\n }\n finally {\n clearTimeout(timeoutId)\n }\n}\n\n/** ORPCError / AbortError / 其他异常 → 标准化 HaiResult 错误。 */\nfunction mapClientError(error: unknown) {\n if (error instanceof ORPCError) {\n // 保留 ORPCError 的原始 code / status / data,供上层区分具体业务异常(不仅是 HTTP 状态码)。\n const detail = { orpcCode: error.code, status: error.status, data: error.data }\n if (error.status === 401)\n return err(HaiApiClientError.UNAUTHORIZED, error.message, detail)\n if (error.status === 403)\n return err(HaiApiClientError.FORBIDDEN, error.message, detail)\n if (error.status === 404)\n return err(HaiApiClientError.NOT_FOUND, error.message, detail)\n return err(HaiApiClientError.SERVER_ERROR, error.message, detail)\n }\n if (error instanceof DOMException && error.name === 'AbortError') {\n return err(HaiApiClientError.TIMEOUT, apiClientM('apiClient_timeout'), error)\n }\n return err(HaiApiClientError.NETWORK_ERROR, apiClientM('apiClient_networkError'), error)\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/api-client",
3
3
  "type": "module",
4
- "version": "0.1.0-alpha.13",
4
+ "version": "0.1.0-alpha.16",
5
5
  "description": "Hai Framework universal HTTP client with Bearer token and API contract support.",
6
6
  "license": "Apache-2.0",
7
7
  "exports": {
@@ -20,8 +20,13 @@
20
20
  "access": "public"
21
21
  },
22
22
  "dependencies": {
23
+ "@orpc/client": "^1.14.3",
24
+ "@orpc/contract": "^1.14.3",
25
+ "@orpc/openapi-client": "^1.14.3",
23
26
  "zod": "^4.3.6",
24
- "@h-ai/core": "0.1.0-alpha.13"
27
+ "@h-ai/api-contract": "0.1.0-alpha.16",
28
+ "@h-ai/crypto": "0.1.0-alpha.16",
29
+ "@h-ai/core": "0.1.0-alpha.16"
25
30
  },
26
31
  "devDependencies": {
27
32
  "@types/node": "^25.1.0",