feat(image): 新建 knowai-core:1.0.0 镜像并完成推送
Some checks reported errors
continuous-integration/drone/push Build was killed

- 搭建 api、auth、utils 等逻辑模块
- 通过 tsc、eslint、vitest 测试验证

BREAKING CHANGE: 新镜像分支
This commit is contained in:
tobegold574
2025-11-10 20:20:25 +08:00
commit 6a81b7bb13
73 changed files with 10511 additions and 0 deletions

279
api/client.ts Normal file
View File

@@ -0,0 +1,279 @@
import axios from 'axios';
import type { ApiClient } from './types';
import type { AxiosError, AxiosResponse, AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';
import { ApiError } from './errors'; // 直接导入ApiError
// 创建API客户端实例的工厂函数
const createApiClientInstance = (config?: Partial<AxiosRequestConfig>): ApiClient => {
// 创建axios实例
const instance = axios.create({
baseURL: '/api', // Core层使用默认值具体配置由Runtime层注入
timeout: 10000,
headers: {
'Content-Type': 'application/json'
},
withCredentials: true, // 允许跨域携带cookie
...config // 应用传入的配置
});
// 请求拦截器数组
const requestInterceptors: Array<number> = [];
// 响应拦截器数组
const responseInterceptors: Array<number> = [];
// 添加请求拦截器
const addRequestInterceptor = (
onFulfilled?: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = instance.interceptors.request.use(onFulfilled, onRejected);
requestInterceptors.push(handler);
return handler;
};
// 添加响应拦截器
const addResponseInterceptor = (
onFulfilled?: (_response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = instance.interceptors.response.use(onFulfilled, onRejected);
responseInterceptors.push(handler);
return handler;
};
// 移除请求拦截器
const removeRequestInterceptor = (handler: number): void => {
const index = requestInterceptors.indexOf(handler);
if (index !== -1) {
instance.interceptors.request.eject(handler);
requestInterceptors.splice(index, 1);
}
};
// 移除响应拦截器
const removeResponseInterceptor = (handler: number): void => {
const index = responseInterceptors.indexOf(handler);
if (index !== -1) {
instance.interceptors.response.eject(handler);
responseInterceptors.splice(index, 1);
}
};
// 设置默认配置
const setDefaults = (_config: Partial<AxiosRequestConfig>): void => {
Object.assign(instance.defaults, _config);
};
// 更新基础URL - 专门用于Runtime层配置
const setBaseURL = (baseURL: string): void => {
instance.defaults.baseURL = baseURL;
};
// 创建新实例 - 用于跨域请求等特殊场景
const createInstance = (config?: Partial<AxiosRequestConfig>): ApiClient => {
// 创建新的axios实例
const newInstance = axios.create({
...instance.defaults,
...config
});
// 为新实例创建拦截器数组
const newRequestInterceptors: Array<number> = [];
const newResponseInterceptors: Array<number> = [];
// 复制拦截器
requestInterceptors.forEach(handler => {
// 由于AxiosInterceptorManager类型定义中没有handlers属性
// 我们使用类型断言来访问内部属性
type RequestHandlerType = {
id: number;
fulfilled: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
rejected: (_error: unknown) => unknown;
};
type RequestManagerType = {
handlers?: Array<RequestHandlerType>;
};
const requestManager = instance.interceptors.request as unknown as RequestManagerType;
const originalInterceptor = requestManager.handlers?.find((h: RequestHandlerType) => h.id === handler);
if (originalInterceptor) {
const newHandler = newInstance.interceptors.request.use(
originalInterceptor.fulfilled,
originalInterceptor.rejected
);
newRequestInterceptors.push(newHandler);
}
});
responseInterceptors.forEach(handler => {
// 由于AxiosInterceptorManager类型定义中没有handlers属性
// 我们使用类型断言来访问内部属性
type ResponseHandlerType = {
id: number;
fulfilled: (_response: AxiosResponse) => AxiosResponse;
rejected: (_error: AxiosError) => unknown;
};
type ResponseManagerType = {
handlers?: Array<ResponseHandlerType>;
};
const responseManager = instance.interceptors.response as unknown as ResponseManagerType;
const originalInterceptor = responseManager.handlers?.find((h: ResponseHandlerType) => h.id === handler);
if (originalInterceptor) {
const newHandler = newInstance.interceptors.response.use(
originalInterceptor.fulfilled,
originalInterceptor.rejected
);
newResponseInterceptors.push(newHandler);
}
});
// 返回一个符合ApiClient接口的对象
return {
request: async <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
try {
const response = await newInstance.request<T>(config);
return response.data;
} catch (error) {
// 直接使用ApiError.fromAxiosError静态方法处理错误
return Promise.reject(ApiError.fromAxiosError(error as AxiosError));
}
},
get: <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'GET', url }).then((res: AxiosResponse<T>) => res.data);
},
post: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'POST', url, data }).then((res: AxiosResponse<T>) => res.data);
},
put: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'PUT', url, data }).then((res: AxiosResponse<T>) => res.data);
},
delete: <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'DELETE', url }).then((res: AxiosResponse<T>) => res.data);
},
patch: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'PATCH', url, data }).then((res: AxiosResponse<T>) => res.data);
},
setDefaults: (_config: Partial<AxiosRequestConfig>): void => {
Object.assign(newInstance.defaults, _config);
},
setBaseURL: (baseURL: string): void => {
newInstance.defaults.baseURL = baseURL;
},
createInstance: (newConfig?: Partial<AxiosRequestConfig>): ApiClient => {
// 手动处理headers字段的类型转换
const { headers, ...otherDefaults } = newInstance.defaults;
const configWithTypedHeaders: Partial<AxiosRequestConfig> = {
...otherDefaults,
...newConfig
};
// 只有当headers存在时才添加
if (headers) {
// 手动转换headers字段确保类型安全
const convertedHeaders: Record<string, string | number | boolean> = {};
Object.entries(headers).forEach(([key, value]) => {
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
convertedHeaders[key] = value;
}
});
configWithTypedHeaders.headers = convertedHeaders;
}
return createInstance(configWithTypedHeaders);
},
addRequestInterceptor: (
onFulfilled?: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = newInstance.interceptors.request.use(onFulfilled, onRejected);
newRequestInterceptors.push(handler);
return handler;
},
addResponseInterceptor: (
onFulfilled?: (_response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = newInstance.interceptors.response.use(onFulfilled, onRejected);
newResponseInterceptors.push(handler);
return handler;
},
removeRequestInterceptor: (handler: number): void => {
const index = newRequestInterceptors.indexOf(handler);
if (index !== -1) {
newInstance.interceptors.request.eject(handler);
newRequestInterceptors.splice(index, 1);
}
},
removeResponseInterceptor: (handler: number): void => {
const index = newResponseInterceptors.indexOf(handler);
if (index !== -1) {
newInstance.interceptors.response.eject(handler);
newResponseInterceptors.splice(index, 1);
}
}
};
};
// 基础请求方法
const request = async <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
try {
const response = await instance.request<T>(config);
return response.data;
} catch (error) {
// 直接使用ApiError.fromAxiosError静态方法处理错误
return Promise.reject(ApiError.fromAxiosError(error as AxiosError));
}
};
// HTTP方法简写
const get = <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'GET', url });
};
const post = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'POST', url, data });
};
const put = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'PUT', url, data });
};
const del = <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'DELETE', url });
};
const patch = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'PATCH', url, data });
};
return {
request,
get,
post,
put,
delete: del,
patch,
setDefaults,
setBaseURL,
createInstance,
addRequestInterceptor,
addResponseInterceptor,
removeRequestInterceptor,
removeResponseInterceptor
};
};
// 默认实例(单例)
const apiClient = createApiClientInstance();
// 工厂函数
const createApiClient = (config?: Partial<AxiosRequestConfig>) => {
return createApiClientInstance(config);
};
// 导出API客户端和工厂函数
export { apiClient, createApiClient };