@vafast/api-client 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +282 -0
- package/build.ts +37 -0
- package/bun.lock +569 -0
- package/example/index.ts +255 -0
- package/package.json +53 -0
- package/src/core/api-client.ts +389 -0
- package/src/core/typed-client.ts +305 -0
- package/src/index.ts +73 -0
- package/src/types/index.ts +133 -0
- package/src/utils/index.ts +232 -0
- package/src/websocket/websocket-client.ts +347 -0
- package/test/api-client.test.ts +262 -0
- package/test/basic.test.ts +55 -0
- package/test/typed-client.test.ts +304 -0
- package/test/utils.test.ts +363 -0
- package/test/websocket.test.ts +434 -0
- package/tsconfig.dts.json +20 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +23 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// 导入必要的类型
|
|
2
|
+
import type {
|
|
3
|
+
ApiClientConfig,
|
|
4
|
+
RequestConfig,
|
|
5
|
+
ApiResponse,
|
|
6
|
+
QueryParams,
|
|
7
|
+
PathParams,
|
|
8
|
+
RequestBody,
|
|
9
|
+
Server,
|
|
10
|
+
Route,
|
|
11
|
+
RouteHandler,
|
|
12
|
+
InferRouteHandler,
|
|
13
|
+
InferServer,
|
|
14
|
+
RoutePath,
|
|
15
|
+
RouteMethod,
|
|
16
|
+
RouteHandlerType,
|
|
17
|
+
} from "../types";
|
|
18
|
+
import { VafastApiClient } from "./api-client";
|
|
19
|
+
import { replacePathParams } from "../utils";
|
|
20
|
+
|
|
21
|
+
// 类型推断类型 - 重新导出
|
|
22
|
+
export type { InferRouteHandler, InferServer, RoutePath, RouteMethod, RouteHandlerType };
|
|
23
|
+
|
|
24
|
+
// 定义 HTTP 方法类型
|
|
25
|
+
type HttpMethod = "get" | "post" | "put" | "delete" | "patch" | "head" | "options";
|
|
26
|
+
|
|
27
|
+
// 类型守卫函数
|
|
28
|
+
function isHttpMethod(prop: string): prop is HttpMethod {
|
|
29
|
+
return ["get", "post", "put", "delete", "patch", "head", "options"].includes(prop);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 类型安全的 HTTP 方法映射
|
|
33
|
+
type HttpMethodMap = {
|
|
34
|
+
get: (path: string, query?: QueryParams, config?: RequestConfig) => Promise<ApiResponse<unknown>>;
|
|
35
|
+
post: (path: string, body?: RequestBody, config?: RequestConfig) => Promise<ApiResponse<unknown>>;
|
|
36
|
+
put: (path: string, body?: RequestBody, config?: RequestConfig) => Promise<ApiResponse<unknown>>;
|
|
37
|
+
delete: (path: string, config?: RequestConfig) => Promise<ApiResponse<unknown>>;
|
|
38
|
+
patch: (
|
|
39
|
+
path: string,
|
|
40
|
+
body?: RequestBody,
|
|
41
|
+
config?: RequestConfig
|
|
42
|
+
) => Promise<ApiResponse<unknown>>;
|
|
43
|
+
head: (path: string, config?: RequestConfig) => Promise<ApiResponse<unknown>>;
|
|
44
|
+
options: (path: string, config?: RequestConfig) => Promise<ApiResponse<unknown>>;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// 改进的参数类型判断
|
|
48
|
+
function isRequestBody(value: unknown): value is RequestBody {
|
|
49
|
+
return (
|
|
50
|
+
value !== null &&
|
|
51
|
+
typeof value === "object" &&
|
|
52
|
+
!Array.isArray(value) &&
|
|
53
|
+
!(value instanceof FormData)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isQueryParams(value: unknown): value is QueryParams {
|
|
58
|
+
return (
|
|
59
|
+
value !== null &&
|
|
60
|
+
typeof value === "object" &&
|
|
61
|
+
!Array.isArray(value) &&
|
|
62
|
+
!(value instanceof FormData)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 改进的路径构建函数
|
|
67
|
+
function normalizePath(basePath: string, prop: string): string {
|
|
68
|
+
const cleanBase = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
|
|
69
|
+
const cleanProp = prop.startsWith("/") ? prop.slice(1) : prop;
|
|
70
|
+
return `${cleanBase}/${cleanProp}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 类型安全的客户端接口
|
|
74
|
+
export interface TypedApiClient<T> {
|
|
75
|
+
// 基础 HTTP 方法
|
|
76
|
+
get<P extends string>(
|
|
77
|
+
path: P,
|
|
78
|
+
query?: QueryParams,
|
|
79
|
+
config?: RequestConfig
|
|
80
|
+
): Promise<ApiResponse<unknown>>;
|
|
81
|
+
|
|
82
|
+
post<P extends string>(
|
|
83
|
+
path: P,
|
|
84
|
+
body?: RequestBody,
|
|
85
|
+
config?: RequestConfig
|
|
86
|
+
): Promise<ApiResponse<unknown>>;
|
|
87
|
+
|
|
88
|
+
put<P extends string>(
|
|
89
|
+
path: P,
|
|
90
|
+
body?: RequestBody,
|
|
91
|
+
config?: RequestConfig
|
|
92
|
+
): Promise<ApiResponse<unknown>>;
|
|
93
|
+
|
|
94
|
+
delete<P extends string>(path: P, config?: RequestConfig): Promise<ApiResponse<unknown>>;
|
|
95
|
+
|
|
96
|
+
patch<P extends string>(
|
|
97
|
+
path: P,
|
|
98
|
+
body?: RequestBody,
|
|
99
|
+
config?: RequestConfig
|
|
100
|
+
): Promise<ApiResponse<unknown>>;
|
|
101
|
+
|
|
102
|
+
head<P extends string>(path: P, config?: RequestConfig): Promise<ApiResponse<unknown>>;
|
|
103
|
+
|
|
104
|
+
options<P extends string>(path: P, config?: RequestConfig): Promise<ApiResponse<unknown>>;
|
|
105
|
+
|
|
106
|
+
// 动态路径方法
|
|
107
|
+
[key: string]: unknown;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 创建类型安全的 API 客户端
|
|
112
|
+
*/
|
|
113
|
+
export function createTypedClient<T extends Server>(
|
|
114
|
+
server: T,
|
|
115
|
+
config?: ApiClientConfig
|
|
116
|
+
): TypedApiClient<T> {
|
|
117
|
+
const apiClient = new VafastApiClient(config);
|
|
118
|
+
|
|
119
|
+
// 创建代理对象,支持链式调用
|
|
120
|
+
return new Proxy({} as TypedApiClient<T>, {
|
|
121
|
+
get(target, prop: string) {
|
|
122
|
+
// 如果是 HTTP 方法,返回对应的请求方法
|
|
123
|
+
if (isHttpMethod(prop)) {
|
|
124
|
+
return (path: string, bodyOrQuery?: RequestBody | QueryParams, config?: RequestConfig) => {
|
|
125
|
+
const method = prop.toUpperCase();
|
|
126
|
+
|
|
127
|
+
if (method === "GET" || method === "HEAD" || method === "OPTIONS") {
|
|
128
|
+
// 暂时使用类型断言,保持功能正常
|
|
129
|
+
return (apiClient as any)[prop](path, bodyOrQuery as QueryParams, config);
|
|
130
|
+
} else {
|
|
131
|
+
return (apiClient as any)[prop](path, bodyOrQuery as RequestBody, config);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 如果是路径段,返回新的代理对象
|
|
137
|
+
return createPathProxy(apiClient, prop);
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 创建路径代理
|
|
144
|
+
*/
|
|
145
|
+
function createPathProxy(apiClient: VafastApiClient, basePath: string) {
|
|
146
|
+
return new Proxy({} as Record<string, unknown>, {
|
|
147
|
+
get(target, prop: string) {
|
|
148
|
+
const currentPath = normalizePath(basePath, prop);
|
|
149
|
+
|
|
150
|
+
// 如果是 HTTP 方法,返回对应的请求方法
|
|
151
|
+
if (isHttpMethod(prop)) {
|
|
152
|
+
return (bodyOrQuery?: RequestBody | QueryParams, config?: RequestConfig) => {
|
|
153
|
+
const method = prop.toUpperCase();
|
|
154
|
+
|
|
155
|
+
if (method === "GET" || method === "HEAD" || method === "OPTIONS") {
|
|
156
|
+
// 使用类型安全的方法调用
|
|
157
|
+
const clientMethod = apiClient[prop as keyof HttpMethodMap];
|
|
158
|
+
const queryParams = bodyOrQuery as QueryParams | undefined;
|
|
159
|
+
return (clientMethod as any)(basePath, queryParams, config);
|
|
160
|
+
} else {
|
|
161
|
+
const clientMethod = apiClient[prop as keyof HttpMethodMap];
|
|
162
|
+
const requestBody = bodyOrQuery as RequestBody | undefined;
|
|
163
|
+
return (clientMethod as any)(basePath, requestBody, config);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 如果是路径段,返回新的代理对象
|
|
169
|
+
return createPathProxy(apiClient, currentPath);
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
// 处理函数调用(用于动态路径)
|
|
173
|
+
apply(target, thisArg, args) {
|
|
174
|
+
const [params, bodyOrQuery, config] = args as [
|
|
175
|
+
PathParams,
|
|
176
|
+
RequestBody | QueryParams,
|
|
177
|
+
RequestConfig?
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
// 替换路径参数
|
|
181
|
+
const resolvedPath = replacePathParams(basePath, params || {});
|
|
182
|
+
|
|
183
|
+
// 使用改进的参数类型判断
|
|
184
|
+
if (bodyOrQuery && isRequestBody(bodyOrQuery) && !config) {
|
|
185
|
+
// 如果有 body 参数,使用 POST 方法
|
|
186
|
+
return apiClient.post(resolvedPath, bodyOrQuery, config);
|
|
187
|
+
} else {
|
|
188
|
+
// 否则使用 GET
|
|
189
|
+
return apiClient.get(resolvedPath, bodyOrQuery as QueryParams, config);
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 创建基于路由的客户端
|
|
197
|
+
*/
|
|
198
|
+
export function createRouteBasedClient<T extends Server>(
|
|
199
|
+
server: T,
|
|
200
|
+
config?: ApiClientConfig
|
|
201
|
+
): TypedApiClient<T> {
|
|
202
|
+
const apiClient = new VafastApiClient(config);
|
|
203
|
+
|
|
204
|
+
// 分析服务器路由,创建类型安全的客户端
|
|
205
|
+
return createTypedClientFromRoutes(server, apiClient);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 从路由创建类型安全的客户端
|
|
210
|
+
*/
|
|
211
|
+
function createTypedClientFromRoutes<T extends Server>(
|
|
212
|
+
server: T,
|
|
213
|
+
apiClient: VafastApiClient
|
|
214
|
+
): TypedApiClient<T> {
|
|
215
|
+
// 这里可以根据实际的路由结构来生成客户端
|
|
216
|
+
// 由于 Vafast 的路由结构,我们需要动态分析
|
|
217
|
+
|
|
218
|
+
return new Proxy({} as TypedApiClient<T>, {
|
|
219
|
+
get(target, prop: string) {
|
|
220
|
+
// 返回一个可以处理动态路径的对象
|
|
221
|
+
return createDynamicPathHandler(apiClient, prop);
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 创建动态路径处理器
|
|
228
|
+
*/
|
|
229
|
+
function createDynamicPathHandler(apiClient: VafastApiClient, basePath: string) {
|
|
230
|
+
return new Proxy({} as Record<string, unknown>, {
|
|
231
|
+
get(target, prop: string) {
|
|
232
|
+
const currentPath = normalizePath(basePath, prop);
|
|
233
|
+
|
|
234
|
+
// 如果是 HTTP 方法
|
|
235
|
+
if (isHttpMethod(prop)) {
|
|
236
|
+
return (bodyOrQuery?: RequestBody | QueryParams, config?: RequestConfig) => {
|
|
237
|
+
const method = prop.toUpperCase();
|
|
238
|
+
|
|
239
|
+
if (method === "GET" || method === "HEAD" || method === "OPTIONS") {
|
|
240
|
+
// 使用类型安全的方法调用
|
|
241
|
+
const clientMethod = apiClient[prop as keyof HttpMethodMap];
|
|
242
|
+
const queryParams = bodyOrQuery as QueryParams | undefined;
|
|
243
|
+
return clientMethod(basePath, queryParams, config);
|
|
244
|
+
} else {
|
|
245
|
+
const clientMethod = apiClient[prop as keyof HttpMethodMap];
|
|
246
|
+
const requestBody = bodyOrQuery as RequestBody | undefined;
|
|
247
|
+
return (clientMethod as any)(basePath, requestBody, config);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 继续构建路径
|
|
253
|
+
return createDynamicPathHandler(apiClient, currentPath);
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
// 处理函数调用
|
|
257
|
+
apply(target, thisArg, args) {
|
|
258
|
+
const [params, bodyOrQuery, config] = args as [
|
|
259
|
+
PathParams,
|
|
260
|
+
RequestBody | QueryParams,
|
|
261
|
+
RequestConfig?
|
|
262
|
+
];
|
|
263
|
+
|
|
264
|
+
// 替换路径参数
|
|
265
|
+
const resolvedPath = replacePathParams(basePath, params || {});
|
|
266
|
+
|
|
267
|
+
// 使用改进的参数类型判断
|
|
268
|
+
if (bodyOrQuery && isRequestBody(bodyOrQuery) && !config) {
|
|
269
|
+
return apiClient.post(resolvedPath, bodyOrQuery);
|
|
270
|
+
} else {
|
|
271
|
+
return apiClient.get(resolvedPath, bodyOrQuery as QueryParams, config);
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* 创建简单的类型安全客户端
|
|
279
|
+
*/
|
|
280
|
+
export function createSimpleClient<T extends Server>(
|
|
281
|
+
server: T,
|
|
282
|
+
config?: ApiClientConfig
|
|
283
|
+
): TypedApiClient<T> {
|
|
284
|
+
const apiClient = new VafastApiClient(config);
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
get: (path: string, query?: QueryParams, config?: RequestConfig) =>
|
|
288
|
+
(apiClient as any).get(path, query, config),
|
|
289
|
+
|
|
290
|
+
post: (path: string, body?: RequestBody, config?: RequestConfig) =>
|
|
291
|
+
(apiClient as any).post(path, body, config),
|
|
292
|
+
|
|
293
|
+
put: (path: string, body?: RequestBody, config?: RequestConfig) =>
|
|
294
|
+
(apiClient as any).put(path, body, config),
|
|
295
|
+
|
|
296
|
+
delete: (path: string, config?: RequestConfig) => (apiClient as any).delete(path, config),
|
|
297
|
+
|
|
298
|
+
patch: (path: string, body?: RequestBody, config?: RequestConfig) =>
|
|
299
|
+
(apiClient as any).patch(path, body, config),
|
|
300
|
+
|
|
301
|
+
head: (path: string, config?: RequestConfig) => (apiClient as any).head(path, config),
|
|
302
|
+
|
|
303
|
+
options: (path: string, config?: RequestConfig) => (apiClient as any).options(path, config),
|
|
304
|
+
} as TypedApiClient<T>;
|
|
305
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// 核心 API 客户端
|
|
2
|
+
export { VafastApiClient } from './core/api-client'
|
|
3
|
+
export {
|
|
4
|
+
createTypedClient,
|
|
5
|
+
createRouteBasedClient,
|
|
6
|
+
createSimpleClient,
|
|
7
|
+
type TypedApiClient
|
|
8
|
+
} from './core/typed-client'
|
|
9
|
+
|
|
10
|
+
// WebSocket 客户端
|
|
11
|
+
export {
|
|
12
|
+
VafastWebSocketClient,
|
|
13
|
+
createWebSocketClient,
|
|
14
|
+
createTypedWebSocketClient
|
|
15
|
+
} from './websocket/websocket-client'
|
|
16
|
+
|
|
17
|
+
// 类型定义
|
|
18
|
+
export type {
|
|
19
|
+
// 基础类型
|
|
20
|
+
HTTPMethod,
|
|
21
|
+
RequestConfig,
|
|
22
|
+
ApiResponse,
|
|
23
|
+
QueryParams,
|
|
24
|
+
PathParams,
|
|
25
|
+
RequestBody,
|
|
26
|
+
ApiClientConfig,
|
|
27
|
+
|
|
28
|
+
// 类型推断
|
|
29
|
+
InferRouteHandler,
|
|
30
|
+
InferServer,
|
|
31
|
+
RoutePath,
|
|
32
|
+
RouteMethod,
|
|
33
|
+
RouteHandlerType,
|
|
34
|
+
|
|
35
|
+
// WebSocket 类型
|
|
36
|
+
WebSocketEvent,
|
|
37
|
+
WebSocketClient,
|
|
38
|
+
|
|
39
|
+
// 文件类型
|
|
40
|
+
FileUpload,
|
|
41
|
+
ApiFormData,
|
|
42
|
+
|
|
43
|
+
// 中间件和拦截器
|
|
44
|
+
ApiMiddleware,
|
|
45
|
+
Interceptor,
|
|
46
|
+
|
|
47
|
+
// 配置类型
|
|
48
|
+
CacheConfig,
|
|
49
|
+
RetryConfig,
|
|
50
|
+
LogConfig
|
|
51
|
+
} from './types'
|
|
52
|
+
|
|
53
|
+
// 工具函数
|
|
54
|
+
export {
|
|
55
|
+
buildQueryString,
|
|
56
|
+
replacePathParams,
|
|
57
|
+
isFile,
|
|
58
|
+
isFileUpload,
|
|
59
|
+
hasFiles,
|
|
60
|
+
createFormData,
|
|
61
|
+
deepMerge,
|
|
62
|
+
delay,
|
|
63
|
+
exponentialBackoff,
|
|
64
|
+
validateStatus,
|
|
65
|
+
parseResponse,
|
|
66
|
+
createError,
|
|
67
|
+
cloneRequest,
|
|
68
|
+
isRetryableError
|
|
69
|
+
} from './utils'
|
|
70
|
+
|
|
71
|
+
// 默认导出
|
|
72
|
+
import { VafastApiClient } from './core/api-client'
|
|
73
|
+
export default VafastApiClient
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// 基础类型定义
|
|
2
|
+
export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'
|
|
3
|
+
|
|
4
|
+
// 简化的 vafast 类型定义
|
|
5
|
+
export interface Server {
|
|
6
|
+
routes: Record<string, Route>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Route {
|
|
10
|
+
method: string
|
|
11
|
+
path: string
|
|
12
|
+
handler: RouteHandler
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RouteHandler {
|
|
16
|
+
(req: unknown, res: unknown): unknown
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 请求配置
|
|
21
|
+
*/
|
|
22
|
+
export interface RequestConfig {
|
|
23
|
+
headers?: Record<string, string>
|
|
24
|
+
timeout?: number
|
|
25
|
+
retries?: number
|
|
26
|
+
retryDelay?: number
|
|
27
|
+
body?: RequestBody
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 响应类型
|
|
31
|
+
export interface ApiResponse<T = unknown> {
|
|
32
|
+
data: T | null
|
|
33
|
+
error: Error | null
|
|
34
|
+
status: number
|
|
35
|
+
headers: Headers
|
|
36
|
+
response: Response
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 查询参数类型
|
|
40
|
+
export type QueryParams = Record<string, string | number | boolean | undefined | null>
|
|
41
|
+
|
|
42
|
+
// 路径参数类型
|
|
43
|
+
export type PathParams = Record<string, string | number>
|
|
44
|
+
|
|
45
|
+
// 请求体类型
|
|
46
|
+
export type RequestBody = unknown
|
|
47
|
+
|
|
48
|
+
// API 客户端配置
|
|
49
|
+
export interface ApiClientConfig extends RequestConfig {
|
|
50
|
+
baseURL?: string
|
|
51
|
+
defaultHeaders?: Record<string, string>
|
|
52
|
+
timeout?: number
|
|
53
|
+
retries?: number
|
|
54
|
+
retryDelay?: number
|
|
55
|
+
validateStatus?: (status: number) => boolean
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 类型推断类型
|
|
59
|
+
export type InferRouteHandler<T> = T extends RouteHandler ? T : never
|
|
60
|
+
export type InferServer<T> = T extends Server ? T : never
|
|
61
|
+
export type RoutePath<T> = T extends Route ? T['path'] : never
|
|
62
|
+
export type RouteMethod<T> = T extends Route ? T['method'] : never
|
|
63
|
+
export type RouteHandlerType<T> = T extends Route ? T['handler'] : never
|
|
64
|
+
|
|
65
|
+
// WebSocket 事件类型
|
|
66
|
+
export interface WebSocketEvent<T = unknown> {
|
|
67
|
+
type: string
|
|
68
|
+
data: T
|
|
69
|
+
timestamp: number
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// WebSocket 客户端类型
|
|
73
|
+
export interface WebSocketClient {
|
|
74
|
+
connect(): Promise<void>
|
|
75
|
+
disconnect(): void
|
|
76
|
+
send(data: unknown): void
|
|
77
|
+
on(event: string, callback: (data: unknown) => void): void
|
|
78
|
+
off(event: string, callback: (data: unknown) => void): void
|
|
79
|
+
isConnected(): boolean
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 文件上传类型
|
|
83
|
+
export interface FileUpload {
|
|
84
|
+
file: File | Blob
|
|
85
|
+
filename?: string
|
|
86
|
+
contentType?: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 表单数据类型(重命名避免与全局 FormData 冲突)
|
|
90
|
+
export interface ApiFormData {
|
|
91
|
+
[key: string]: string | number | boolean | File | Blob | FileUpload | ApiFormData | (string | number | boolean | File | Blob | FileUpload | ApiFormData)[] | unknown
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 中间件类型
|
|
95
|
+
export interface ApiMiddleware {
|
|
96
|
+
name: string
|
|
97
|
+
onRequest?: (request: Request, config: RequestConfig) => Request | Promise<Request>
|
|
98
|
+
onResponse?: (response: Response, config: RequestConfig) => Response | Promise<Response>
|
|
99
|
+
onError?: (error: Error, config: RequestConfig) => Error | Promise<Error>
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 缓存配置类型
|
|
103
|
+
export interface CacheConfig {
|
|
104
|
+
enabled: boolean
|
|
105
|
+
ttl: number
|
|
106
|
+
maxSize: number
|
|
107
|
+
strategy: 'memory' | 'localStorage' | 'sessionStorage'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 重试配置类型
|
|
111
|
+
export interface RetryConfig {
|
|
112
|
+
enabled: boolean
|
|
113
|
+
maxRetries: number
|
|
114
|
+
retryDelay: number
|
|
115
|
+
backoffMultiplier: number
|
|
116
|
+
retryableStatuses: number[]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 拦截器类型
|
|
120
|
+
export interface Interceptor {
|
|
121
|
+
request?: (config: RequestConfig) => RequestConfig | Promise<RequestConfig>
|
|
122
|
+
response?: (response: Response) => Response | Promise<Response>
|
|
123
|
+
error?: (error: Error) => Error | Promise<Error>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 日志配置类型
|
|
127
|
+
export interface LogConfig {
|
|
128
|
+
enabled: boolean
|
|
129
|
+
level: 'debug' | 'info' | 'warn' | 'error'
|
|
130
|
+
format: 'json' | 'text'
|
|
131
|
+
includeHeaders: boolean
|
|
132
|
+
includeBody: boolean
|
|
133
|
+
}
|