feat(reset): 以构造器模式重构

- 加了大文件传输自定义分片协议

BREAKING CHANGES: 0.1.0(latest)
This commit is contained in:
tobegold574
2025-11-30 20:27:53 +08:00
parent c5853847ae
commit 382e3aff21
82 changed files with 1421 additions and 7010 deletions

128
decorators/common.ts Normal file
View File

@@ -0,0 +1,128 @@
import { setMeta, getMeta, type ApiMethodMeta } from './meta';
import { AxiosHttpClient, type BaseError } from '../client';
// ApiError错误接口
export interface ApiError {
status: number; // 状态码来自response的status
statusText: string; // 状态文本来自response的msg
code: string; // 错误码(字符串)
message: string; // 报错信息(字符串)
// 没有别的细节了,错误码直接对照常量映射
}
// 客户端请求参数接口
export interface ClientRequestParams {
method: string;
url: string;
query?: Record<string, string | number>;
body?: any;
}
// 创建 AxiosHttpClient 单例实例
const apiClientInstance = new AxiosHttpClient();
/**
* 创建 HTTP 方法装饰器的通用函数
* @param method HTTP 方法类型
* @returns 装饰器函数
*/
export function createHttpMethodDecorator(method: ApiMethodMeta['method']) {
return function(path: string) {
return function(_target: Object, context: ClassMethodDecoratorContext) {
// 确保只应用于方法
if (context.kind !== 'method') {
throw new Error(`HTTP method decorator (${method}) can only be applied to methods`);
}
// 获取原始方法
const originalMethod = _target[context.name as keyof Object] as Function;
// 设置元数据
setMeta(originalMethod, 'api', {
method,
path
} as ApiMethodMeta);
};
};
}
/**
* 为 API 客户端类绑定 HTTP 客户端实例的装饰器
* @description 该装饰器对当前类注入 AxiosHttpClient 实例
*/
export function ApiClientBound<T extends { new (...args: any[]): { client: AxiosHttpClient } }>(target: T, _context: ClassDecoratorContext<T>) {
// 定义一个新类,继承自目标类
return class extends target {
// 在构造函数中初始化客户端实例
constructor(...args: any[]) {
super(...args);
// 添加客户端实例
this.client = apiClientInstance;
}
}
}
/**
* 请求执行装饰器,自动处理 API 调用逻辑
*/
export function Request(target: Object, context: ClassMethodDecoratorContext) {
const methodName = String(context.name);
// 确保只应用于方法
if (context.kind !== 'method') {
throw new Error('Request decorator can only be applied to methods');
}
// 保存原始方法
const originalMethod = target[context.name as keyof Object] as Function;
// 定义新的方法实现
async function replacementMethod(this: { client: { request: (params: ClientRequestParams) => Promise<any> } }, ...args: any[]) {
// 获取 API 元数据
const meta = getMeta(originalMethod, 'api') as ApiMethodMeta | undefined;
if (!meta) {
throw new Error(`Missing API metadata on ${methodName}. Please use an HTTP method decorator (GET, POST, etc.)`);
}
const { method, path } = meta;
// 处理请求参数
const params = args[0] ?? {};
const body = args[1];
// 替换路径中的动态参数段
let finalPath = path.replace(/:([\w]+)/g, (_, key) => {
const paramValue = params[key];
if (paramValue === undefined) {
throw new Error(`Missing required path parameter '${key}' for API endpoint '${path}'`);
}
return String(paramValue);
});
// 执行请求并处理错误
try {
return await this.client.request({
method,
url: finalPath,
query: params,
body,
});
} catch (error: BaseError | any) {
// 确保错误对象符合 ApiError 接口
const apiError: ApiError = {
status: error.response?.status || 500,
statusText: error.response?.msg || 'Internal Server Error',
code: error?.code || 'UNKNOWN_ERROR',
message: error?.message || 'An unexpected error occurred',
};
throw apiError;
}
}
// TS5+直接返回新方法定义
return replacementMethod;
}

View File

@@ -0,0 +1,41 @@
import { createHttpMethodDecorator } from './common';
/**
* GET 请求装饰器
* @param path API 路径,支持 :param 格式的动态参数
*/
export function GET(path: string) {
return createHttpMethodDecorator('GET')(path);
}
/**
* POST 请求装饰器
* @param path API 路径,支持 :param 格式的动态参数
*/
export function POST(path: string) {
return createHttpMethodDecorator('POST')(path);
}
/**
* PUT 请求装饰器
* @param path API 路径,支持 :param 格式的动态参数
*/
export function PUT(path: string) {
return createHttpMethodDecorator('PUT')(path);
}
/**
* DELETE 请求装饰器
* @param path API 路径,支持 :param 格式的动态参数
*/
export function DELETE(path: string) {
return createHttpMethodDecorator('DELETE')(path);
}
/**
* PATCH 请求装饰器
* @param path API 路径,支持 :param 格式的动态参数
*/
export function PATCH(path: string) {
return createHttpMethodDecorator('PATCH')(path);
}

2
decorators/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './http-methods';
export * from './common';

35
decorators/meta.ts Normal file
View File

@@ -0,0 +1,35 @@
/**
* API 方法元数据接口
*/
export interface ApiMethodMeta {
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
path: string;
}
// 使用 WeakMap 存储元数据,避免内存泄漏
const metaStore = new WeakMap<Function, Map<string, ApiMethodMeta>>();
/**
* 设置函数的元数据
* @param target 目标函数
* @param key 元数据键名
* @param value 元数据值
*/
export function setMeta(target: Function, _key: string, value: ApiMethodMeta): void {
let map = metaStore.get(target);
if (!map) {
map = new Map();
metaStore.set(target, map);
}
map.set(_key, value);
}
/**
* 获取函数的元数据
* @param target 目标函数
* @param key 元数据键名
* @returns 元数据值或undefined
*/
export function getMeta(target: Function, key: string): ApiMethodMeta | undefined {
return metaStore.get(target)?.get(key);
}