@longzai-intelligence-transport/http-core 0.1.0
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 +64 -0
- package/dist/index.d.ts +3136 -0
- package/dist/index.js +3 -0
- package/package.json +52 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3136 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { ZodError, ZodType } from "zod";
|
|
3
|
+
import { CompactPaginatedResult, CursorPaginatedResult, CursorPaginationParams, CursorPaginationParamsSchema, OffsetPaginatedResult, OffsetPaginationParams, OffsetPaginationParamsSchema, PaginatedResult, PaginationParams, PaginationParamsSchema, calculateOffset, calculateTotalPages, createPaginatedResult, normalizePagination } from "@longzai-intelligence/pagination";
|
|
4
|
+
import { Result } from "@longzai-intelligence/shared-kernel";
|
|
5
|
+
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
6
|
+
import { Logger } from "@longzai-intelligence/logger-core";
|
|
7
|
+
|
|
8
|
+
//#region src/contract/response.schema.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* API 响应数据类型
|
|
11
|
+
*
|
|
12
|
+
* 统一的 API 响应结构,支持服务端和客户端两种使用场景:
|
|
13
|
+
* - 服务端:包含 data/message/timestamp
|
|
14
|
+
* - 客户端:包含 data/error
|
|
15
|
+
*
|
|
16
|
+
* @typeParam T - 响应数据类型
|
|
17
|
+
*/
|
|
18
|
+
type ApiResponse<T = unknown> = {
|
|
19
|
+
/**
|
|
20
|
+
* 请求是否成功
|
|
21
|
+
*/
|
|
22
|
+
success: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* 响应数据,成功时存在
|
|
25
|
+
*/
|
|
26
|
+
data?: T;
|
|
27
|
+
/**
|
|
28
|
+
* 响应消息,失败时存在
|
|
29
|
+
*/
|
|
30
|
+
message?: string;
|
|
31
|
+
/**
|
|
32
|
+
* 错误信息,客户端错误响应时存在
|
|
33
|
+
*/
|
|
34
|
+
error?: ApiError;
|
|
35
|
+
/**
|
|
36
|
+
* 响应时间戳,服务端生成
|
|
37
|
+
*/
|
|
38
|
+
timestamp?: number;
|
|
39
|
+
/**
|
|
40
|
+
* 元数据,用于传递额外信息(如重试状态)
|
|
41
|
+
*/
|
|
42
|
+
metadata?: Record<string, unknown>;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* API 成功响应类型
|
|
46
|
+
*
|
|
47
|
+
* @typeParam T - 响应数据类型
|
|
48
|
+
*/
|
|
49
|
+
type ApiSuccessResponse<T> = ApiResponse<T> & ApiSuccessResponseData<T>;
|
|
50
|
+
/**
|
|
51
|
+
* API 成功响应数据
|
|
52
|
+
*
|
|
53
|
+
* @typeParam T - 响应数据类型
|
|
54
|
+
*/
|
|
55
|
+
type ApiSuccessResponseData<T> = {
|
|
56
|
+
/**
|
|
57
|
+
* 请求是否成功
|
|
58
|
+
*/
|
|
59
|
+
success: true;
|
|
60
|
+
/**
|
|
61
|
+
* 响应数据
|
|
62
|
+
*/
|
|
63
|
+
data: T;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* API 失败响应类型
|
|
67
|
+
*
|
|
68
|
+
* @typeParam T - 错误数据类型
|
|
69
|
+
*/
|
|
70
|
+
type ApiFailResponse<T = unknown> = ApiResponse<T> & ApiFailResponseData;
|
|
71
|
+
/**
|
|
72
|
+
* API 失败响应数据
|
|
73
|
+
*
|
|
74
|
+
* @typeParam T - 错误数据类型
|
|
75
|
+
*/
|
|
76
|
+
type ApiFailResponseData = {
|
|
77
|
+
/**
|
|
78
|
+
* 请求是否成功
|
|
79
|
+
*/
|
|
80
|
+
success: false;
|
|
81
|
+
/**
|
|
82
|
+
* 响应消息
|
|
83
|
+
*/
|
|
84
|
+
message: string;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* API 列表数据类型
|
|
88
|
+
*
|
|
89
|
+
* @typeParam T - 列表项类型
|
|
90
|
+
*/
|
|
91
|
+
type ApiListData<T> = {
|
|
92
|
+
/**
|
|
93
|
+
* 列表项数组
|
|
94
|
+
*/
|
|
95
|
+
items: T[];
|
|
96
|
+
/**
|
|
97
|
+
* 总数
|
|
98
|
+
*/
|
|
99
|
+
total: number;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* API 分页列表数据类型
|
|
103
|
+
*
|
|
104
|
+
* 基于 @longzai-intelligence/pagination 的 PaginatedResult
|
|
105
|
+
* 适用于需要完整分页控制的场景(带跳页、总数显示)
|
|
106
|
+
*
|
|
107
|
+
* @typeParam T - 列表项类型
|
|
108
|
+
*/
|
|
109
|
+
type ApiPaginatedListData<T> = PaginatedResult<T>;
|
|
110
|
+
/**
|
|
111
|
+
* API 紧凑分页列表数据类型
|
|
112
|
+
*
|
|
113
|
+
* 基于 @longzai-intelligence/pagination 的 CompactPaginatedResult
|
|
114
|
+
* 适用于不需要跳页的列表场景(如下拉加载更多)
|
|
115
|
+
*
|
|
116
|
+
* @typeParam T - 列表项类型
|
|
117
|
+
*/
|
|
118
|
+
type ApiCompactPaginatedListData<T> = CompactPaginatedResult<T>;
|
|
119
|
+
/**
|
|
120
|
+
* 重新导出 @longzai-intelligence/pagination 的分页类型和工具函数
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* API 错误 Schema
|
|
124
|
+
*
|
|
125
|
+
* 描述 API 错误响应的结构
|
|
126
|
+
*/
|
|
127
|
+
declare const ApiErrorSchema: z.ZodObject<{
|
|
128
|
+
code: z.ZodString;
|
|
129
|
+
message: z.ZodString;
|
|
130
|
+
details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
131
|
+
}, z.core.$strip>;
|
|
132
|
+
/**
|
|
133
|
+
* API 错误类型
|
|
134
|
+
*/
|
|
135
|
+
type ApiError = z.infer<typeof ApiErrorSchema>;
|
|
136
|
+
/**
|
|
137
|
+
* API 响应 Schema 工厂
|
|
138
|
+
*
|
|
139
|
+
* 创建包含 success/data/message/error/timestamp 结构的 Zod Schema
|
|
140
|
+
*
|
|
141
|
+
* @typeParam T - 数据部分的 Zod Schema 类型
|
|
142
|
+
* @param dataSchema - 数据部分的 Zod Schema
|
|
143
|
+
* @returns API 响应 Zod Schema
|
|
144
|
+
*/
|
|
145
|
+
declare const ApiResponseSchema: <T extends z.ZodTypeAny>(dataSchema: T) => z.ZodObject<{
|
|
146
|
+
success: z.ZodBoolean;
|
|
147
|
+
data: z.ZodOptional<T>;
|
|
148
|
+
message: z.ZodOptional<z.ZodString>;
|
|
149
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
150
|
+
code: z.ZodString;
|
|
151
|
+
message: z.ZodString;
|
|
152
|
+
details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
153
|
+
}, z.core.$strip>>;
|
|
154
|
+
timestamp: z.ZodOptional<z.ZodNumber>;
|
|
155
|
+
}, z.core.$strip>;
|
|
156
|
+
/**
|
|
157
|
+
* API 列表数据 Schema 工厂
|
|
158
|
+
*
|
|
159
|
+
* 创建包含 items/total 结构的 Zod Schema
|
|
160
|
+
*
|
|
161
|
+
* @typeParam T - 列表项的 Zod Schema 类型
|
|
162
|
+
* @param itemSchema - 列表项的 Zod Schema
|
|
163
|
+
* @returns 列表数据 Zod Schema
|
|
164
|
+
*/
|
|
165
|
+
declare const ApiListDataSchema: <T extends z.ZodTypeAny>(itemSchema: T) => z.ZodObject<{
|
|
166
|
+
items: z.ZodArray<T>;
|
|
167
|
+
total: z.ZodNumber;
|
|
168
|
+
}, z.core.$strip>;
|
|
169
|
+
/**
|
|
170
|
+
* API 分页列表数据 Schema 工厂
|
|
171
|
+
*
|
|
172
|
+
* 基于 @longzai-intelligence/pagination 的 createPaginatedResultSchema
|
|
173
|
+
*
|
|
174
|
+
* @typeParam T - 列表项 Schema 类型
|
|
175
|
+
* @param itemSchema - 列表项的 Zod Schema
|
|
176
|
+
* @returns 分页列表数据 Zod Schema
|
|
177
|
+
*/
|
|
178
|
+
declare const ApiPaginatedListDataSchema: <T extends z.ZodTypeAny>(itemSchema: T) => z.ZodObject<{
|
|
179
|
+
items: z.ZodArray<T>;
|
|
180
|
+
total: z.ZodNumber;
|
|
181
|
+
page: z.ZodNumber;
|
|
182
|
+
pageSize: z.ZodNumber;
|
|
183
|
+
totalPages: z.ZodNumber;
|
|
184
|
+
hasNextPage: z.ZodBoolean;
|
|
185
|
+
hasPreviousPage: z.ZodBoolean;
|
|
186
|
+
}, z.core.$strip>;
|
|
187
|
+
/**
|
|
188
|
+
* API 紧凑分页列表数据 Schema 工厂
|
|
189
|
+
*
|
|
190
|
+
* 基于 @longzai-intelligence/pagination 的 createCompactPaginatedResultSchema
|
|
191
|
+
*
|
|
192
|
+
* @typeParam T - 列表项 Schema 类型
|
|
193
|
+
* @param itemSchema - 列表项的 Zod Schema
|
|
194
|
+
* @returns 紧凑分页列表数据 Zod Schema
|
|
195
|
+
*/
|
|
196
|
+
declare const ApiCompactPaginatedListDataSchema: <T extends z.ZodTypeAny>(itemSchema: T) => z.ZodObject<{
|
|
197
|
+
items: z.ZodArray<T>;
|
|
198
|
+
total: z.ZodNumber;
|
|
199
|
+
hasMore: z.ZodBoolean;
|
|
200
|
+
}, z.core.$strip>;
|
|
201
|
+
/**
|
|
202
|
+
* 空响应 Schema
|
|
203
|
+
*
|
|
204
|
+
* 用于无返回数据的 API 响应
|
|
205
|
+
*/
|
|
206
|
+
declare const EmptyResponseSchema: z.ZodObject<{
|
|
207
|
+
success: z.ZodBoolean;
|
|
208
|
+
data: z.ZodOptional<z.ZodVoid>;
|
|
209
|
+
message: z.ZodOptional<z.ZodString>;
|
|
210
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
211
|
+
code: z.ZodString;
|
|
212
|
+
message: z.ZodString;
|
|
213
|
+
details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
214
|
+
}, z.core.$strip>>;
|
|
215
|
+
timestamp: z.ZodOptional<z.ZodNumber>;
|
|
216
|
+
}, z.core.$strip>;
|
|
217
|
+
/**
|
|
218
|
+
* 空响应类型
|
|
219
|
+
*/
|
|
220
|
+
type EmptyResponse = ApiResponse<void>;
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/contract/type-utils.types.d.ts
|
|
223
|
+
/**
|
|
224
|
+
* 从对象类型中提取 data 字段的类型
|
|
225
|
+
*
|
|
226
|
+
* 如果对象有 data 字段,则返回 data 字段的类型(排除 undefined),否则返回原类型
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* type Result = ExtractData<{ data: string }>; // string
|
|
230
|
+
*
|
|
231
|
+
* @typeParam T - 对象类型
|
|
232
|
+
*/
|
|
233
|
+
type ExtractData<T> = T extends DataField<infer D> ? NonNullable<D> : T;
|
|
234
|
+
/**
|
|
235
|
+
* 数据字段类型
|
|
236
|
+
*
|
|
237
|
+
* @typeParam D - data 字段的类型
|
|
238
|
+
*/
|
|
239
|
+
type DataField<D> = {
|
|
240
|
+
/**
|
|
241
|
+
* 可选的 data 字段
|
|
242
|
+
*/
|
|
243
|
+
data?: D;
|
|
244
|
+
} | {
|
|
245
|
+
/**
|
|
246
|
+
* 必选的 data 字段
|
|
247
|
+
*/
|
|
248
|
+
data: D;
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* 从 ApiResponse 中解包数据类型
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* type Result = UnwrapApiResponse<ApiResponse<string>>; // string
|
|
255
|
+
*
|
|
256
|
+
* @typeParam T - ApiResponse 类型
|
|
257
|
+
*/
|
|
258
|
+
type UnwrapApiResponse<T> = T extends ApiResponse<infer D> ? D : T;
|
|
259
|
+
/**
|
|
260
|
+
* 从 ApiListData 中解包数组项类型
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* type Result = UnwrapApiListData<ApiListData<string>>; // string[]
|
|
264
|
+
*
|
|
265
|
+
* @typeParam T - ApiListData 类型
|
|
266
|
+
*/
|
|
267
|
+
type UnwrapApiListData<T> = T extends ApiListData<infer I> ? I[] : T;
|
|
268
|
+
/**
|
|
269
|
+
* 从 ApiPaginatedListData 中解包数组项类型
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* type Result = UnwrapApiPaginatedListData<ApiPaginatedListData<string>>; // string[]
|
|
273
|
+
*
|
|
274
|
+
* @typeParam T - ApiPaginatedListData 类型
|
|
275
|
+
*/
|
|
276
|
+
type UnwrapApiPaginatedListData<T> = T extends ApiPaginatedListData<infer I> ? I[] : T;
|
|
277
|
+
/**
|
|
278
|
+
* 从可能为 null 或 undefined 的类型中提取非空类型
|
|
279
|
+
*
|
|
280
|
+
* @typeParam T - 输入类型
|
|
281
|
+
*/
|
|
282
|
+
type NonNullableData<T> = NonNullable<T>;
|
|
283
|
+
/**
|
|
284
|
+
* 从数组类型中提取元素类型
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* type Result = ArrayElement<string[]>; // string
|
|
288
|
+
*
|
|
289
|
+
* @typeParam T - 数组类型
|
|
290
|
+
*/
|
|
291
|
+
type ArrayElement<T> = T extends (infer E)[] ? E : never;
|
|
292
|
+
/**
|
|
293
|
+
* 从 Promise 类型中提取解析后的类型
|
|
294
|
+
*
|
|
295
|
+
* @typeParam T - Promise 类型
|
|
296
|
+
*/
|
|
297
|
+
type AwaitedData<T> = Awaited<T>;
|
|
298
|
+
/**
|
|
299
|
+
* 从函数返回类型中提取类型
|
|
300
|
+
*
|
|
301
|
+
* @typeParam T - 函数类型
|
|
302
|
+
*/
|
|
303
|
+
type ReturnDataType<T extends (...args: unknown[]) => unknown> = ReturnType<T>;
|
|
304
|
+
/**
|
|
305
|
+
* 深度部分类型
|
|
306
|
+
*
|
|
307
|
+
* 支持嵌套对象的部分更新
|
|
308
|
+
*
|
|
309
|
+
* @typeParam T - 对象类型
|
|
310
|
+
*/
|
|
311
|
+
type DeepPartial<T> = { [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P] };
|
|
312
|
+
/**
|
|
313
|
+
* 深度必需类型
|
|
314
|
+
*
|
|
315
|
+
* 将所有嵌套的可选字段变为必需
|
|
316
|
+
*
|
|
317
|
+
* @typeParam T - 对象类型
|
|
318
|
+
*/
|
|
319
|
+
type DeepRequired<T> = { [P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P] };
|
|
320
|
+
/**
|
|
321
|
+
* 深度只读类型
|
|
322
|
+
*
|
|
323
|
+
* 将所有嵌套的字段变为只读
|
|
324
|
+
*
|
|
325
|
+
* @typeParam T - 对象类型
|
|
326
|
+
*/
|
|
327
|
+
type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P] };
|
|
328
|
+
/**
|
|
329
|
+
* 从对象类型中选取特定值类型的键
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* type Result = PickByValue<{ a: string; b: number }, string>; // { a: string }
|
|
333
|
+
*
|
|
334
|
+
* @typeParam T - 对象类型
|
|
335
|
+
* @typeParam V - 值类型
|
|
336
|
+
*/
|
|
337
|
+
type PickByValue<T, V> = Pick<T, { [K in keyof T]: T[K] extends V ? K : never }[keyof T]>;
|
|
338
|
+
/**
|
|
339
|
+
* 从对象类型中排除特定值类型的键
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* type Result = OmitByValue<{ a: string; b: number }, string>; // { b: number }
|
|
343
|
+
*
|
|
344
|
+
* @typeParam T - 对象类型
|
|
345
|
+
* @typeParam V - 值类型
|
|
346
|
+
*/
|
|
347
|
+
type OmitByValue<T, V> = Pick<T, { [K in keyof T]: T[K] extends V ? never : K }[keyof T]>;
|
|
348
|
+
/**
|
|
349
|
+
* 将对象类型的键转换为联合类型
|
|
350
|
+
*
|
|
351
|
+
* @typeParam T - 对象类型
|
|
352
|
+
*/
|
|
353
|
+
type ObjectKeys<T extends object> = keyof T;
|
|
354
|
+
/**
|
|
355
|
+
* 将对象类型的值转换为联合类型
|
|
356
|
+
*
|
|
357
|
+
* @typeParam T - 对象类型
|
|
358
|
+
*/
|
|
359
|
+
type ObjectValues<T extends object> = T[keyof T];
|
|
360
|
+
/**
|
|
361
|
+
* 将两个对象类型合并
|
|
362
|
+
*
|
|
363
|
+
* 后者的属性会覆盖前者的同名属性
|
|
364
|
+
*
|
|
365
|
+
* @typeParam T - 第一个对象类型
|
|
366
|
+
* @typeParam U - 第二个对象类型
|
|
367
|
+
*/
|
|
368
|
+
type Merge<T, U> = Omit<T, keyof U> & U;
|
|
369
|
+
/**
|
|
370
|
+
* 将对象类型的所有键变为可选
|
|
371
|
+
*
|
|
372
|
+
* @typeParam T - 对象类型
|
|
373
|
+
*/
|
|
374
|
+
type OptionalKeys<T> = { [K in keyof T]?: T[K] };
|
|
375
|
+
/**
|
|
376
|
+
* 将对象类型的所有键变为必需
|
|
377
|
+
*
|
|
378
|
+
* @typeParam T - 对象类型
|
|
379
|
+
*/
|
|
380
|
+
type RequiredKeys<T> = { [K in keyof T]-?: T[K] };
|
|
381
|
+
/**
|
|
382
|
+
* 从对象类型中提取可选键
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* type Result = OptionalKeyOf<{ a: string; b?: number }>; // 'b'
|
|
386
|
+
*
|
|
387
|
+
* @typeParam T - 对象类型
|
|
388
|
+
*/
|
|
389
|
+
type OptionalKeyOf<T extends object> = { [K in keyof T]-?: undefined extends T[K] ? K : never }[keyof T];
|
|
390
|
+
/**
|
|
391
|
+
* 从对象类型中提取必需键
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* type Result = RequiredKeyOf<{ a: string; b?: number }>; // 'a'
|
|
395
|
+
*
|
|
396
|
+
* @typeParam T - 对象类型
|
|
397
|
+
*/
|
|
398
|
+
type RequiredKeyOf<T extends object> = { [K in keyof T]-?: undefined extends T[K] ? never : K }[keyof T];
|
|
399
|
+
//#endregion
|
|
400
|
+
//#region src/contract/request.types.d.ts
|
|
401
|
+
/**
|
|
402
|
+
* HTTP 请求方法类型
|
|
403
|
+
*/
|
|
404
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
405
|
+
/**
|
|
406
|
+
* 请求配置类型
|
|
407
|
+
*
|
|
408
|
+
* 每次请求的额外配置选项,如认证、自定义头、超时等
|
|
409
|
+
*/
|
|
410
|
+
type RequestConfig = {
|
|
411
|
+
/**
|
|
412
|
+
* 是否携带认证令牌
|
|
413
|
+
*/
|
|
414
|
+
withAuth?: boolean;
|
|
415
|
+
/**
|
|
416
|
+
* 自定义请求头
|
|
417
|
+
*/
|
|
418
|
+
headers?: Record<string, string>;
|
|
419
|
+
/**
|
|
420
|
+
* 请求超时时间(毫秒)
|
|
421
|
+
*/
|
|
422
|
+
timeout?: number;
|
|
423
|
+
/**
|
|
424
|
+
* 中断信号
|
|
425
|
+
*/
|
|
426
|
+
signal?: AbortSignal;
|
|
427
|
+
/**
|
|
428
|
+
* 是否携带 CSRF 令牌,与 RouteDefinition.csrf 配合使用
|
|
429
|
+
*/
|
|
430
|
+
withCsrf?: boolean;
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* 路由定义类型
|
|
434
|
+
*
|
|
435
|
+
* 描述一个 API 路由的完整契约,包括方法、路径、参数、请求体和响应
|
|
436
|
+
*
|
|
437
|
+
* @typeParam TMethod - HTTP 方法类型
|
|
438
|
+
* @typeParam TPath - 路径模板字符串
|
|
439
|
+
* @typeParam TParams - 路径参数 Zod Schema
|
|
440
|
+
* @typeParam TQuery - 查询参数 Zod Schema
|
|
441
|
+
* @typeParam TBody - 请求体 Zod Schema
|
|
442
|
+
* @typeParam TResponse - 响应 Zod Schema
|
|
443
|
+
*/
|
|
444
|
+
type RouteDefinition<TMethod extends HttpMethod = HttpMethod, TPath extends string = string, TParams extends ZodType | undefined = ZodType | undefined, TQuery extends ZodType | undefined = ZodType | undefined, TBody extends ZodType | undefined = ZodType | undefined, TResponse extends ZodType = ZodType> = {
|
|
445
|
+
/**
|
|
446
|
+
* HTTP 方法
|
|
447
|
+
*/
|
|
448
|
+
method: TMethod;
|
|
449
|
+
/**
|
|
450
|
+
* 路径模板,支持 :param 形式的路径参数
|
|
451
|
+
*/
|
|
452
|
+
path: TPath;
|
|
453
|
+
/**
|
|
454
|
+
* 路径参数 Schema
|
|
455
|
+
*/
|
|
456
|
+
params?: TParams;
|
|
457
|
+
/**
|
|
458
|
+
* 查询参数 Schema
|
|
459
|
+
*/
|
|
460
|
+
query?: TQuery;
|
|
461
|
+
/**
|
|
462
|
+
* 请求体 Schema
|
|
463
|
+
*/
|
|
464
|
+
body?: TBody;
|
|
465
|
+
/**
|
|
466
|
+
* 响应 Schema
|
|
467
|
+
*/
|
|
468
|
+
response: TResponse;
|
|
469
|
+
/**
|
|
470
|
+
* 接口摘要描述
|
|
471
|
+
*/
|
|
472
|
+
summary?: string;
|
|
473
|
+
/**
|
|
474
|
+
* 接口标签分组
|
|
475
|
+
*/
|
|
476
|
+
tags?: string[];
|
|
477
|
+
/**
|
|
478
|
+
* 是否需要 CSRF 令牌保护,默认 false
|
|
479
|
+
*/
|
|
480
|
+
csrf?: boolean;
|
|
481
|
+
/**
|
|
482
|
+
* 请求内容类型
|
|
483
|
+
*
|
|
484
|
+
* - 'json':application/json(默认)
|
|
485
|
+
* - 'formData':multipart/form-data,用于文件上传
|
|
486
|
+
*/
|
|
487
|
+
contentType?: 'json' | 'formData';
|
|
488
|
+
/**
|
|
489
|
+
* 基础路径(NestJS 方法装饰器使用的相对路径)
|
|
490
|
+
*
|
|
491
|
+
* 由 defineRouteGroup.define 自动设置,值为原始子路径(不含分组前缀)。
|
|
492
|
+
* 未通过分组创建的路由不包含此字段。
|
|
493
|
+
*/
|
|
494
|
+
basePath?: string;
|
|
495
|
+
};
|
|
496
|
+
/**
|
|
497
|
+
* 从路由定义中推断路径参数类型
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* type Params = InferRouteParams<typeof routes.detail>;
|
|
501
|
+
* // { id: string }
|
|
502
|
+
*
|
|
503
|
+
* @typeParam T - 路由定义类型
|
|
504
|
+
*/
|
|
505
|
+
type InferRouteParams<T extends RouteDefinition> = T extends RouteDefinition<HttpMethod, string, infer P, ZodType | undefined, ZodType | undefined, ZodType> ? [P] extends [ZodType] ? P['_output'] : undefined : undefined;
|
|
506
|
+
/**
|
|
507
|
+
* 从路由定义中推断查询参数类型
|
|
508
|
+
*
|
|
509
|
+
* @example
|
|
510
|
+
* type Query = InferRouteQuery<typeof routes.list>;
|
|
511
|
+
* // { page?: number; pageSize?: number }
|
|
512
|
+
*
|
|
513
|
+
* @typeParam T - 路由定义类型
|
|
514
|
+
*/
|
|
515
|
+
type InferRouteQuery<T extends RouteDefinition> = T extends RouteDefinition<HttpMethod, string, ZodType | undefined, infer Q, ZodType | undefined, ZodType> ? [Q] extends [ZodType] ? Q['_output'] : undefined : undefined;
|
|
516
|
+
/**
|
|
517
|
+
* 从路由定义中推断请求体类型
|
|
518
|
+
*
|
|
519
|
+
* @example
|
|
520
|
+
* type Body = InferRouteBody<typeof routes.create>;
|
|
521
|
+
* // { name: string; price: number }
|
|
522
|
+
*
|
|
523
|
+
* @typeParam T - 路由定义类型
|
|
524
|
+
*/
|
|
525
|
+
type InferRouteBody<T extends RouteDefinition> = T extends RouteDefinition<HttpMethod, string, ZodType | undefined, ZodType | undefined, infer B, ZodType> ? [B] extends [ZodType] ? B['_output'] : undefined : undefined;
|
|
526
|
+
/**
|
|
527
|
+
* 从路由定义中推断响应数据类型
|
|
528
|
+
*
|
|
529
|
+
* 自动解包 ApiResponse 和 PaginatedResponse
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* type Data = InferRouteResponse<typeof routes.detail>;
|
|
533
|
+
* // User
|
|
534
|
+
*
|
|
535
|
+
* @typeParam T - 路由定义类型
|
|
536
|
+
*/
|
|
537
|
+
type InferRouteResponse<T extends RouteDefinition> = T extends RouteDefinition<HttpMethod, string, ZodType | undefined, ZodType | undefined, ZodType | undefined, infer R> ? [R] extends [ZodType] ? ExtractData<R['_output']> : never : never;
|
|
538
|
+
/**
|
|
539
|
+
* 从路由定义中推断完整的响应类型
|
|
540
|
+
*
|
|
541
|
+
* 包含 ApiResponse 包装
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* type Response = InferRouteFullResponse<typeof routes.detail>;
|
|
545
|
+
* // ApiResponse<User>
|
|
546
|
+
*
|
|
547
|
+
* @typeParam T - 路由定义类型
|
|
548
|
+
*/
|
|
549
|
+
type InferRouteFullResponse<T extends RouteDefinition> = T extends RouteDefinition<HttpMethod, string, ZodType | undefined, ZodType | undefined, ZodType | undefined, infer R> ? [R] extends [ZodType] ? ApiResponse<ExtractData<R['_output']>> : never : never;
|
|
550
|
+
/**
|
|
551
|
+
* 从路由定义中推断分页响应的项类型
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* type Item = InferRouteItem<typeof routes.list>;
|
|
555
|
+
* // User
|
|
556
|
+
*
|
|
557
|
+
* @typeParam T - 路由定义类型
|
|
558
|
+
*/
|
|
559
|
+
type InferRouteItem<T extends RouteDefinition> = InferRouteResponse<T> extends ApiListData<infer I> ? I : never;
|
|
560
|
+
/**
|
|
561
|
+
* 从路由定义中推断控制器方法的返回值类型
|
|
562
|
+
*
|
|
563
|
+
* 包含 Promise + ApiResponse 包装,可直接用作控制器方法返回类型标注
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* type Return = InferRouteReturn<typeof routes.detail>;
|
|
567
|
+
* // Promise<ApiResponse<User>>
|
|
568
|
+
*
|
|
569
|
+
* @typeParam T - 路由定义类型
|
|
570
|
+
*/
|
|
571
|
+
type InferRouteReturn<T extends RouteDefinition> = Promise<InferRouteFullResponse<T>>;
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region src/interceptors/interceptor.types.d.ts
|
|
574
|
+
/**
|
|
575
|
+
* 请求拦截器上下文
|
|
576
|
+
*
|
|
577
|
+
* 包含请求的所有信息,拦截器可修改并返回新的上下文
|
|
578
|
+
*/
|
|
579
|
+
type RequestInterceptorContext = {
|
|
580
|
+
/**
|
|
581
|
+
* 完整请求 URL
|
|
582
|
+
*/
|
|
583
|
+
url: string;
|
|
584
|
+
/**
|
|
585
|
+
* HTTP 方法
|
|
586
|
+
*/
|
|
587
|
+
method: HttpMethod;
|
|
588
|
+
/**
|
|
589
|
+
* 请求头
|
|
590
|
+
*/
|
|
591
|
+
headers: Record<string, string>;
|
|
592
|
+
/**
|
|
593
|
+
* 路径参数
|
|
594
|
+
*/
|
|
595
|
+
params?: Record<string, string | number>;
|
|
596
|
+
/**
|
|
597
|
+
* 查询参数
|
|
598
|
+
*/
|
|
599
|
+
query?: Record<string, unknown>;
|
|
600
|
+
/**
|
|
601
|
+
* 请求体
|
|
602
|
+
*/
|
|
603
|
+
body?: unknown;
|
|
604
|
+
/**
|
|
605
|
+
* 路由定义
|
|
606
|
+
*/
|
|
607
|
+
route?: RouteDefinition;
|
|
608
|
+
/**
|
|
609
|
+
* 请求配置
|
|
610
|
+
*/
|
|
611
|
+
config?: RequestConfig;
|
|
612
|
+
/**
|
|
613
|
+
* 元数据存储,用于拦截器间传递信息
|
|
614
|
+
*/
|
|
615
|
+
metadata: Record<string, unknown>;
|
|
616
|
+
};
|
|
617
|
+
/**
|
|
618
|
+
* 响应拦截器上下文
|
|
619
|
+
*
|
|
620
|
+
* 包含响应的元信息,拦截器可访问但通常不修改
|
|
621
|
+
*/
|
|
622
|
+
type ResponseInterceptorContext = {
|
|
623
|
+
/**
|
|
624
|
+
* HTTP 状态码
|
|
625
|
+
*/
|
|
626
|
+
status: number;
|
|
627
|
+
/**
|
|
628
|
+
* 响应头
|
|
629
|
+
*/
|
|
630
|
+
headers: Record<string, string>;
|
|
631
|
+
/**
|
|
632
|
+
* 请求上下文(只读引用)
|
|
633
|
+
*/
|
|
634
|
+
request: Readonly<RequestInterceptorContext>;
|
|
635
|
+
};
|
|
636
|
+
/**
|
|
637
|
+
* 请求拦截器接口
|
|
638
|
+
*
|
|
639
|
+
* 在请求发送前执行,可修改请求配置或添加元数据
|
|
640
|
+
*/
|
|
641
|
+
type RequestInterceptor = {
|
|
642
|
+
/**
|
|
643
|
+
* 请求处理函数
|
|
644
|
+
*
|
|
645
|
+
* @param context - 请求上下文
|
|
646
|
+
* @returns 修改后的请求上下文(同步或异步)
|
|
647
|
+
*/
|
|
648
|
+
onRequest?(context: RequestInterceptorContext): RequestInterceptorContext | Promise<RequestInterceptorContext>;
|
|
649
|
+
/**
|
|
650
|
+
* 请求错误处理函数
|
|
651
|
+
*
|
|
652
|
+
* 当请求发送失败时调用,可用于错误转换或日志记录
|
|
653
|
+
*
|
|
654
|
+
* @param error - 原始错误
|
|
655
|
+
* @param context - 请求上下文
|
|
656
|
+
* @returns 转换后的错误或原始错误
|
|
657
|
+
*/
|
|
658
|
+
onError?(error: unknown, context: RequestInterceptorContext): unknown;
|
|
659
|
+
};
|
|
660
|
+
/**
|
|
661
|
+
* 响应拦截器接口
|
|
662
|
+
*
|
|
663
|
+
* 在响应接收后执行,可修改响应数据或处理错误
|
|
664
|
+
*/
|
|
665
|
+
type ResponseInterceptor = {
|
|
666
|
+
/**
|
|
667
|
+
* 响应处理函数
|
|
668
|
+
*
|
|
669
|
+
* @param response - API 响应
|
|
670
|
+
* @param context - 响应上下文
|
|
671
|
+
* @returns 修改后的 API 响应(同步或异步)
|
|
672
|
+
*/
|
|
673
|
+
onResponse?(response: ApiResponse, context: ResponseInterceptorContext): ApiResponse | Promise<ApiResponse>;
|
|
674
|
+
/**
|
|
675
|
+
* 响应错误处理函数
|
|
676
|
+
*
|
|
677
|
+
* 当响应处理失败时调用,可用于错误恢复或重试
|
|
678
|
+
*
|
|
679
|
+
* @param error - 原始错误
|
|
680
|
+
* @param context - 响应上下文
|
|
681
|
+
* @returns 转换后的错误、恢复的响应或原始错误
|
|
682
|
+
*/
|
|
683
|
+
onError?(error: unknown, context: ResponseInterceptorContext): unknown | ApiResponse;
|
|
684
|
+
};
|
|
685
|
+
//#endregion
|
|
686
|
+
//#region src/interceptors/executor.utils.d.ts
|
|
687
|
+
/**
|
|
688
|
+
* HTTP 适配器接口
|
|
689
|
+
*
|
|
690
|
+
* 各运行时环境需实现此接口,拦截器执行器调用适配器执行实际 HTTP 请求
|
|
691
|
+
*/
|
|
692
|
+
type HttpAdapter$1 = {
|
|
693
|
+
/**
|
|
694
|
+
* 执行 HTTP 请求
|
|
695
|
+
*
|
|
696
|
+
* @param context - 请求上下文(已通过请求拦截器处理)
|
|
697
|
+
* @returns 包含状态码、响应头和响应数据的对象
|
|
698
|
+
*/
|
|
699
|
+
execute(context: RequestInterceptorContext): Promise<AdapterResponse>;
|
|
700
|
+
};
|
|
701
|
+
/**
|
|
702
|
+
* 适配器响应类型
|
|
703
|
+
*/
|
|
704
|
+
type AdapterResponse = {
|
|
705
|
+
/**
|
|
706
|
+
* HTTP 状态码
|
|
707
|
+
*/
|
|
708
|
+
status: number;
|
|
709
|
+
/**
|
|
710
|
+
* 响应头
|
|
711
|
+
*/
|
|
712
|
+
headers: Record<string, string>;
|
|
713
|
+
/**
|
|
714
|
+
* 响应数据
|
|
715
|
+
*/
|
|
716
|
+
data: unknown;
|
|
717
|
+
};
|
|
718
|
+
/**
|
|
719
|
+
* 拦截器执行器配置
|
|
720
|
+
*/
|
|
721
|
+
type InterceptorExecutorConfig = {
|
|
722
|
+
/**
|
|
723
|
+
* 请求拦截器列表
|
|
724
|
+
*/
|
|
725
|
+
requestInterceptors: RequestInterceptor[];
|
|
726
|
+
/**
|
|
727
|
+
* 响应拦截器列表
|
|
728
|
+
*/
|
|
729
|
+
responseInterceptors: ResponseInterceptor[];
|
|
730
|
+
/**
|
|
731
|
+
* 未授权回调
|
|
732
|
+
*/
|
|
733
|
+
onUnauthorized?: OnUnauthorizedCallback;
|
|
734
|
+
};
|
|
735
|
+
/**
|
|
736
|
+
* 未授权回调函数类型
|
|
737
|
+
*/
|
|
738
|
+
type OnUnauthorizedCallback = () => void | Promise<void>;
|
|
739
|
+
/**
|
|
740
|
+
* 创建拦截器执行器
|
|
741
|
+
*
|
|
742
|
+
* @param config - 执行器配置
|
|
743
|
+
* @param adapter - HTTP 适配器
|
|
744
|
+
* @returns 执行器实例
|
|
745
|
+
* @throws {@link Error} 当请求执行过程中发生错误时抛出
|
|
746
|
+
*/
|
|
747
|
+
declare function createInterceptorExecutor(config: InterceptorExecutorConfig, adapter: HttpAdapter$1): {
|
|
748
|
+
/**
|
|
749
|
+
* 执行完整请求流程
|
|
750
|
+
*
|
|
751
|
+
* @param context - 请求拦截器上下文
|
|
752
|
+
* @returns 最终 API 响应
|
|
753
|
+
*/
|
|
754
|
+
execute: (context: RequestInterceptorContext) => Promise<ApiResponse>;
|
|
755
|
+
executeRequestInterceptors: (context: RequestInterceptorContext) => Promise<RequestInterceptorContext>;
|
|
756
|
+
executeResponseInterceptors: (response: ApiResponse, context: ResponseInterceptorContext) => Promise<ApiResponse>;
|
|
757
|
+
handleRequestError: (error: unknown, context: RequestInterceptorContext) => Promise<unknown>;
|
|
758
|
+
handleResponseError: (error: unknown, context: ResponseInterceptorContext) => Promise<unknown>;
|
|
759
|
+
};
|
|
760
|
+
/**
|
|
761
|
+
* 从 HttpClientConfig 创建拦截器执行器配置
|
|
762
|
+
*
|
|
763
|
+
* 将旧配置项转换为拦截器
|
|
764
|
+
*
|
|
765
|
+
* @param config - HTTP 客户端配置
|
|
766
|
+
* @returns 拦截器执行器配置
|
|
767
|
+
* @throws {@link Error} 当配置转换失败时抛出错误
|
|
768
|
+
*/
|
|
769
|
+
declare function createExecutorConfigFromClientConfig(config: HttpClientConfig): InterceptorExecutorConfig;
|
|
770
|
+
//#endregion
|
|
771
|
+
//#region src/interceptors/auth.interceptor.d.ts
|
|
772
|
+
/**
|
|
773
|
+
* Auth 拦截器配置
|
|
774
|
+
*/
|
|
775
|
+
type AuthInterceptorConfig = {
|
|
776
|
+
/**
|
|
777
|
+
* 是否在请求头中携带认证,默认 true
|
|
778
|
+
* 可通过 RequestConfig.withAuth 覆盖
|
|
779
|
+
*/
|
|
780
|
+
withAuth?: boolean;
|
|
781
|
+
/**
|
|
782
|
+
* Token 前缀,默认 'Bearer'
|
|
783
|
+
*/
|
|
784
|
+
tokenPrefix?: string;
|
|
785
|
+
/**
|
|
786
|
+
* 请求头名称,默认 'Authorization'
|
|
787
|
+
*/
|
|
788
|
+
headerName?: string;
|
|
789
|
+
};
|
|
790
|
+
/**
|
|
791
|
+
* 创建 Bearer Token 认证拦截器
|
|
792
|
+
*
|
|
793
|
+
* 自动从 TokenProvider 获取令牌并注入 Authorization 头
|
|
794
|
+
*
|
|
795
|
+
* @example
|
|
796
|
+
* ```typescript
|
|
797
|
+
* import {
|
|
798
|
+
* createAuthTokenInterceptor,
|
|
799
|
+
* createHttpClient,
|
|
800
|
+
* } from '@longzai-intelligence-transport/http';
|
|
801
|
+
*
|
|
802
|
+
* const tokenProvider = {
|
|
803
|
+
* getToken: () => localStorage.getItem('token'),
|
|
804
|
+
* setToken: (token) => localStorage.setItem('token', token),
|
|
805
|
+
* removeToken: () => localStorage.removeItem('token'),
|
|
806
|
+
* };
|
|
807
|
+
*
|
|
808
|
+
* const client = createHttpClient({
|
|
809
|
+
* baseUrl: 'https://api.example.com',
|
|
810
|
+
* requestInterceptors: [createAuthTokenInterceptor(tokenProvider)],
|
|
811
|
+
* });
|
|
812
|
+
* ```;
|
|
813
|
+
*
|
|
814
|
+
* @param tokenProvider - 令牌提供者
|
|
815
|
+
* @param config - 配置选项
|
|
816
|
+
* @returns 请求拦截器
|
|
817
|
+
*/
|
|
818
|
+
declare function createAuthTokenInterceptor(tokenProvider: TokenProvider, config?: AuthInterceptorConfig): RequestInterceptor;
|
|
819
|
+
//#endregion
|
|
820
|
+
//#region src/interceptors/auth-strategy.interceptor.d.ts
|
|
821
|
+
/**
|
|
822
|
+
* 创建多策略认证拦截器
|
|
823
|
+
*
|
|
824
|
+
* 根据 AuthStrategy 类型分发认证逻辑:
|
|
825
|
+
* - bearer: 注入 Authorization 头
|
|
826
|
+
* - cookie: 设置 withCredentials/credentials
|
|
827
|
+
* - custom: 调用 injector 函数
|
|
828
|
+
* - none: 不注入任何认证信息
|
|
829
|
+
*
|
|
830
|
+
* @example
|
|
831
|
+
* ```typescript
|
|
832
|
+
* import {
|
|
833
|
+
* createAuthStrategyInterceptor,
|
|
834
|
+
* createHttpClient,
|
|
835
|
+
* } from '@longzai-intelligence-transport/http';
|
|
836
|
+
*
|
|
837
|
+
* // Bearer Token 策略
|
|
838
|
+
* const client = createHttpClient({
|
|
839
|
+
* baseUrl: 'https://api.example.com',
|
|
840
|
+
* requestInterceptors: [
|
|
841
|
+
* createAuthStrategyInterceptor({
|
|
842
|
+
* type: 'bearer',
|
|
843
|
+
* tokenProvider: myTokenProvider,
|
|
844
|
+
* }),
|
|
845
|
+
* ],
|
|
846
|
+
* });
|
|
847
|
+
*
|
|
848
|
+
* // Cookie 策略
|
|
849
|
+
* const cookieClient = createHttpClient({
|
|
850
|
+
* baseUrl: 'https://api.example.com',
|
|
851
|
+
* requestInterceptors: [
|
|
852
|
+
* createAuthStrategyInterceptor({
|
|
853
|
+
* type: 'cookie',
|
|
854
|
+
* credentials: 'include',
|
|
855
|
+
* }),
|
|
856
|
+
* ],
|
|
857
|
+
* });
|
|
858
|
+
* ```;
|
|
859
|
+
*
|
|
860
|
+
* @param strategy - 认证策略
|
|
861
|
+
* @returns 请求拦截器
|
|
862
|
+
*/
|
|
863
|
+
declare function createAuthStrategyInterceptor(strategy: AuthStrategy): RequestInterceptor;
|
|
864
|
+
/**
|
|
865
|
+
* 从 tokenProvider 创建 AuthStrategy
|
|
866
|
+
*
|
|
867
|
+
* @param tokenProvider - 令牌提供者
|
|
868
|
+
* @returns Bearer Token 认证策略
|
|
869
|
+
*/
|
|
870
|
+
declare function createBearerAuthStrategy(tokenProvider: TokenProvider): AuthStrategy;
|
|
871
|
+
/**
|
|
872
|
+
* 创建 Cookie 认证策略
|
|
873
|
+
*
|
|
874
|
+
* @param credentials - 凭证模式
|
|
875
|
+
* @returns Cookie 认证策略
|
|
876
|
+
*/
|
|
877
|
+
declare function createCookieAuthStrategy(credentials?: 'include' | 'same-origin' | 'omit'): AuthStrategy;
|
|
878
|
+
/**
|
|
879
|
+
* 创建自定义认证策略
|
|
880
|
+
*
|
|
881
|
+
* @param injector - 自定义注入器函数
|
|
882
|
+
* @returns 自定义认证策略
|
|
883
|
+
*/
|
|
884
|
+
declare function createCustomAuthStrategy(injector: CustomAuthInjector): AuthStrategy;
|
|
885
|
+
/**
|
|
886
|
+
* 自定义认证注入器类型
|
|
887
|
+
*/
|
|
888
|
+
type CustomAuthInjector = (config: Record<string, unknown>) => Record<string, unknown>;
|
|
889
|
+
/**
|
|
890
|
+
* 创建无认证策略
|
|
891
|
+
*
|
|
892
|
+
* @returns 无认证策略
|
|
893
|
+
*/
|
|
894
|
+
declare function createNoneAuthStrategy(): AuthStrategy;
|
|
895
|
+
//#endregion
|
|
896
|
+
//#region src/interceptors/csrf.interceptor.d.ts
|
|
897
|
+
/**
|
|
898
|
+
* CSRF 拦截器配置
|
|
899
|
+
*/
|
|
900
|
+
type CsrfInterceptorConfig = {
|
|
901
|
+
/**
|
|
902
|
+
* CSRF 请求头名称,默认 'X-CSRF-Token'
|
|
903
|
+
*/
|
|
904
|
+
headerName?: string;
|
|
905
|
+
/**
|
|
906
|
+
* 是否对所有请求注入,默认 false(仅对 csrf: true 的路由注入)
|
|
907
|
+
*/
|
|
908
|
+
injectAll?: boolean;
|
|
909
|
+
/**
|
|
910
|
+
* 令牌获取失败时的行为,默认 'warn'(输出警告)
|
|
911
|
+
*/
|
|
912
|
+
onTokenError?: 'warn' | 'throw' | 'ignore';
|
|
913
|
+
};
|
|
914
|
+
/**
|
|
915
|
+
* 创建 CSRF 令牌拦截器
|
|
916
|
+
*
|
|
917
|
+
* 根据 RouteDefinition.csrf 标记自动注入 CSRF 令牌
|
|
918
|
+
*
|
|
919
|
+
* @example
|
|
920
|
+
* ```typescript
|
|
921
|
+
* import {
|
|
922
|
+
* createCsrfInterceptor,
|
|
923
|
+
* createHttpClient,
|
|
924
|
+
* defineRoute,
|
|
925
|
+
* } from '@longzai-intelligence-transport/http';
|
|
926
|
+
*
|
|
927
|
+
* const csrfProvider = {
|
|
928
|
+
* getToken: () => document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'),
|
|
929
|
+
* };
|
|
930
|
+
*
|
|
931
|
+
* const client = createHttpClient({
|
|
932
|
+
* baseUrl: 'https://api.example.com',
|
|
933
|
+
* requestInterceptors: [createCsrfInterceptor(csrfProvider)],
|
|
934
|
+
* });
|
|
935
|
+
*
|
|
936
|
+
* // 定义需要 CSRF 保护的路由
|
|
937
|
+
* const routes = {
|
|
938
|
+
* create: defineRoute({
|
|
939
|
+
* method: 'POST',
|
|
940
|
+
* path: '/items',
|
|
941
|
+
* csrf: true, // 标记需要 CSRF 保护
|
|
942
|
+
* response: ItemSchema,
|
|
943
|
+
* }),
|
|
944
|
+
* };
|
|
945
|
+
* ```;
|
|
946
|
+
*
|
|
947
|
+
* @param csrfProvider - CSRF 令牌提供者
|
|
948
|
+
* @param config - 配置选项
|
|
949
|
+
* @returns 请求拦截器
|
|
950
|
+
* @throws {@link Error} 当 onTokenError 设置为 'throw' 时,令牌获取失败会抛出错误
|
|
951
|
+
*/
|
|
952
|
+
declare function createCsrfInterceptor(csrfProvider: CsrfProvider, config?: CsrfInterceptorConfig): RequestInterceptor;
|
|
953
|
+
//#endregion
|
|
954
|
+
//#region src/interceptors/transform.interceptor.d.ts
|
|
955
|
+
/**
|
|
956
|
+
* 响应转换器类型
|
|
957
|
+
*/
|
|
958
|
+
type ResponseTransformer$1 = (raw: unknown) => ApiResponse<unknown>;
|
|
959
|
+
/**
|
|
960
|
+
* 创建响应转换拦截器
|
|
961
|
+
*
|
|
962
|
+
* 将非标准后端响应格式转换为 ApiResponse
|
|
963
|
+
*
|
|
964
|
+
* @example
|
|
965
|
+
* ```typescript
|
|
966
|
+
* import {
|
|
967
|
+
* createResponseTransformerInterceptor,
|
|
968
|
+
* createHttpClient,
|
|
969
|
+
* } from '@longzai-intelligence-transport/http';
|
|
970
|
+
*
|
|
971
|
+
* // 后端返回 { ok: true, result: { ... } } 格式
|
|
972
|
+
* const client = createHttpClient({
|
|
973
|
+
* baseUrl: 'https://api.example.com',
|
|
974
|
+
* responseInterceptors: [
|
|
975
|
+
* createResponseTransformerInterceptor((raw) => ({
|
|
976
|
+
* success: (raw as any).ok,
|
|
977
|
+
* data: (raw as any).result,
|
|
978
|
+
* message: (raw as any).message,
|
|
979
|
+
* })),
|
|
980
|
+
* ],
|
|
981
|
+
* });
|
|
982
|
+
* ```;
|
|
983
|
+
*
|
|
984
|
+
* @param transformer - 响应转换函数
|
|
985
|
+
* @returns 响应拦截器
|
|
986
|
+
*/
|
|
987
|
+
declare function createResponseTransformerInterceptor(transformer: ResponseTransformer$1): ResponseInterceptor;
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/interceptors/retry.interceptor.d.ts
|
|
990
|
+
/**
|
|
991
|
+
* 重试配置
|
|
992
|
+
*/
|
|
993
|
+
type RetryConfig = {
|
|
994
|
+
/**
|
|
995
|
+
* 最大重试次数,默认 0(不重试)
|
|
996
|
+
*/
|
|
997
|
+
maxRetries?: number;
|
|
998
|
+
/**
|
|
999
|
+
* 重试延迟(毫秒)或延迟计算函数
|
|
1000
|
+
* 默认指数退避:baseDelay * 2^attempt
|
|
1001
|
+
*/
|
|
1002
|
+
retryDelay?: number | ((attempt: number) => number);
|
|
1003
|
+
/**
|
|
1004
|
+
* 触发重试的 HTTP 状态码,默认 [408, 429, 500, 502, 503, 504]
|
|
1005
|
+
*/
|
|
1006
|
+
retryOn?: number[];
|
|
1007
|
+
/**
|
|
1008
|
+
* 自定义重试条件
|
|
1009
|
+
*/
|
|
1010
|
+
retryCondition?: (error: unknown, context: ResponseInterceptorContext) => boolean;
|
|
1011
|
+
/**
|
|
1012
|
+
* 基础延迟(毫秒),默认 1000
|
|
1013
|
+
*/
|
|
1014
|
+
baseDelay?: number;
|
|
1015
|
+
};
|
|
1016
|
+
/**
|
|
1017
|
+
* 默认触发重试的状态码
|
|
1018
|
+
*/
|
|
1019
|
+
declare const DEFAULT_RETRY_STATUS_CODES: number[];
|
|
1020
|
+
/**
|
|
1021
|
+
* 创建重试拦截器
|
|
1022
|
+
*
|
|
1023
|
+
* 在请求失败时自动重试
|
|
1024
|
+
*
|
|
1025
|
+
* @example
|
|
1026
|
+
* ```typescript
|
|
1027
|
+
* import { createRetryInterceptor, createHttpClient } from '@longzai-intelligence-transport/http';
|
|
1028
|
+
*
|
|
1029
|
+
* const client = createHttpClient({
|
|
1030
|
+
* baseUrl: 'https://api.example.com',
|
|
1031
|
+
* responseInterceptors: [
|
|
1032
|
+
* createRetryInterceptor({
|
|
1033
|
+
* maxRetries: 3,
|
|
1034
|
+
* baseDelay: 1000,
|
|
1035
|
+
* retryOn: [500, 502, 503, 504],
|
|
1036
|
+
* }),
|
|
1037
|
+
* ],
|
|
1038
|
+
* });
|
|
1039
|
+
* ```;
|
|
1040
|
+
*
|
|
1041
|
+
* @param config - 重试配置
|
|
1042
|
+
* @returns 响应拦截器
|
|
1043
|
+
*/
|
|
1044
|
+
declare function createRetryInterceptor(config?: RetryConfig): ResponseInterceptor;
|
|
1045
|
+
/**
|
|
1046
|
+
* 计算指数退避延迟
|
|
1047
|
+
*
|
|
1048
|
+
* @param attempt - 当前尝试次数
|
|
1049
|
+
* @param baseDelay - 基础延迟(毫秒)
|
|
1050
|
+
* @returns 延迟时间(毫秒)
|
|
1051
|
+
*/
|
|
1052
|
+
declare function exponentialBackoff(attempt: number, baseDelay?: number): number;
|
|
1053
|
+
//#endregion
|
|
1054
|
+
//#region src/interceptors/validation.interceptor.d.ts
|
|
1055
|
+
/**
|
|
1056
|
+
* 验证拦截器配置
|
|
1057
|
+
*/
|
|
1058
|
+
type ValidationInterceptorConfig = {
|
|
1059
|
+
/**
|
|
1060
|
+
* 验证模式
|
|
1061
|
+
* - true: 始终验证
|
|
1062
|
+
* - 'development': 仅开发环境验证
|
|
1063
|
+
* - false: 不验证
|
|
1064
|
+
*/
|
|
1065
|
+
mode?: boolean | 'development';
|
|
1066
|
+
/**
|
|
1067
|
+
* 验证失败时的行为,默认 'warn'(输出警告)
|
|
1068
|
+
*/
|
|
1069
|
+
onValidationError?: 'warn' | 'throw' | 'ignore';
|
|
1070
|
+
/**
|
|
1071
|
+
* 日志记录器实例
|
|
1072
|
+
*/
|
|
1073
|
+
logger?: ValidationLogger;
|
|
1074
|
+
};
|
|
1075
|
+
/**
|
|
1076
|
+
* 验证日志函数类型
|
|
1077
|
+
*/
|
|
1078
|
+
type ValidationLogger = Logger;
|
|
1079
|
+
/**
|
|
1080
|
+
* 创建响应验证拦截器
|
|
1081
|
+
*
|
|
1082
|
+
* 在开发环境对响应数据进行运行时 Schema 验证
|
|
1083
|
+
*
|
|
1084
|
+
* @example
|
|
1085
|
+
* ```typescript
|
|
1086
|
+
* import {
|
|
1087
|
+
* createValidationInterceptor,
|
|
1088
|
+
* createHttpClient,
|
|
1089
|
+
* } from '@longzai-intelligence-transport/http';
|
|
1090
|
+
*
|
|
1091
|
+
* const client = createHttpClient({
|
|
1092
|
+
* baseUrl: 'https://api.example.com',
|
|
1093
|
+
* responseInterceptors: [createValidationInterceptor({ mode: 'development' })],
|
|
1094
|
+
* });
|
|
1095
|
+
* ```;
|
|
1096
|
+
*
|
|
1097
|
+
* @param config - 配置选项
|
|
1098
|
+
* @returns 响应拦截器
|
|
1099
|
+
* @throws {@link Error} 当 onValidationError 为 'throw' 时,验证失败会抛出错误
|
|
1100
|
+
*/
|
|
1101
|
+
declare function createValidationInterceptor(config?: ValidationInterceptorConfig): ResponseInterceptor;
|
|
1102
|
+
//#endregion
|
|
1103
|
+
//#region src/interceptors/logging.interceptor.d.ts
|
|
1104
|
+
/**
|
|
1105
|
+
* 日志拦截器配置
|
|
1106
|
+
*/
|
|
1107
|
+
type LoggingInterceptorConfig = {
|
|
1108
|
+
/**
|
|
1109
|
+
* 日志级别,默认 'info'
|
|
1110
|
+
*/
|
|
1111
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
1112
|
+
/**
|
|
1113
|
+
* 是否记录请求体,默认 false
|
|
1114
|
+
*/
|
|
1115
|
+
logBody?: boolean;
|
|
1116
|
+
/**
|
|
1117
|
+
* 是否记录响应体,默认 false
|
|
1118
|
+
*/
|
|
1119
|
+
logResponse?: boolean;
|
|
1120
|
+
/**
|
|
1121
|
+
* 自定义日志函数
|
|
1122
|
+
*/
|
|
1123
|
+
logger?: (level: string, message: string, data?: unknown) => void;
|
|
1124
|
+
};
|
|
1125
|
+
/**
|
|
1126
|
+
* 默认日志函数
|
|
1127
|
+
*
|
|
1128
|
+
* @param level - 日志级别
|
|
1129
|
+
* @param message - 日志消息
|
|
1130
|
+
* @param data - 日志数据
|
|
1131
|
+
*/
|
|
1132
|
+
declare function defaultLogger(level: string, message: string, data?: unknown): void;
|
|
1133
|
+
/**
|
|
1134
|
+
* 创建日志请求拦截器
|
|
1135
|
+
*
|
|
1136
|
+
* @param config - 配置选项
|
|
1137
|
+
* @returns 请求拦截器
|
|
1138
|
+
*/
|
|
1139
|
+
declare function createLoggingRequestInterceptor(config?: LoggingInterceptorConfig): RequestInterceptor;
|
|
1140
|
+
/**
|
|
1141
|
+
* 创建日志响应拦截器
|
|
1142
|
+
*
|
|
1143
|
+
* @param config - 配置选项
|
|
1144
|
+
* @returns 响应拦截器
|
|
1145
|
+
*/
|
|
1146
|
+
declare function createLoggingResponseInterceptor(config?: LoggingInterceptorConfig): ResponseInterceptor;
|
|
1147
|
+
/**
|
|
1148
|
+
* 创建日志拦截器
|
|
1149
|
+
*
|
|
1150
|
+
* 返回请求拦截器和响应拦截器,用于记录请求和响应信息
|
|
1151
|
+
*
|
|
1152
|
+
* @example
|
|
1153
|
+
* ```typescript
|
|
1154
|
+
* import { createLoggingInterceptor, createHttpClient } from '@longzai-intelligence-transport/http';
|
|
1155
|
+
*
|
|
1156
|
+
* const { request, response } = createLoggingInterceptor({ level: 'debug' });
|
|
1157
|
+
*
|
|
1158
|
+
* const client = createHttpClient({
|
|
1159
|
+
* baseUrl: 'https://api.example.com',
|
|
1160
|
+
* requestInterceptors: [request],
|
|
1161
|
+
* responseInterceptors: [response],
|
|
1162
|
+
* });
|
|
1163
|
+
* ```;
|
|
1164
|
+
*
|
|
1165
|
+
* @param config - 配置选项
|
|
1166
|
+
* @returns 包含请求拦截器和响应拦截器的对象
|
|
1167
|
+
*/
|
|
1168
|
+
declare function createLoggingInterceptor(config?: LoggingInterceptorConfig): LoggingInterceptorResult;
|
|
1169
|
+
/**
|
|
1170
|
+
* 日志拦截器结果类型
|
|
1171
|
+
*/
|
|
1172
|
+
type LoggingInterceptorResult = {
|
|
1173
|
+
/**
|
|
1174
|
+
* 请求拦截器
|
|
1175
|
+
*/
|
|
1176
|
+
request: RequestInterceptor;
|
|
1177
|
+
/**
|
|
1178
|
+
* 响应拦截器
|
|
1179
|
+
*/
|
|
1180
|
+
response: ResponseInterceptor;
|
|
1181
|
+
};
|
|
1182
|
+
//#endregion
|
|
1183
|
+
//#region src/interceptors/legacy-converter.utils.d.ts
|
|
1184
|
+
/**
|
|
1185
|
+
* 从旧配置创建请求拦截器
|
|
1186
|
+
*
|
|
1187
|
+
* @param config - HTTP 客户端配置
|
|
1188
|
+
* @returns 请求拦截器列表
|
|
1189
|
+
*/
|
|
1190
|
+
declare function createRequestInterceptorsFromConfig(config: HttpClientConfig): RequestInterceptor[];
|
|
1191
|
+
/**
|
|
1192
|
+
* 从配置创建响应拦截器
|
|
1193
|
+
*
|
|
1194
|
+
* 始终注入验证拦截器(除非 validation === false),
|
|
1195
|
+
* 并追加用户自定义的响应拦截器
|
|
1196
|
+
*
|
|
1197
|
+
* @param config - HTTP 客户端配置
|
|
1198
|
+
* @returns 响应拦截器列表
|
|
1199
|
+
*/
|
|
1200
|
+
declare function createResponseInterceptorsFromConfig(config: HttpClientConfig): ResponseInterceptor[];
|
|
1201
|
+
/**
|
|
1202
|
+
* 检查配置是否使用旧模式
|
|
1203
|
+
*
|
|
1204
|
+
* @param config - HTTP 客户端配置
|
|
1205
|
+
* @returns 是否使用旧模式
|
|
1206
|
+
*/
|
|
1207
|
+
declare function isLegacyConfig(config: HttpClientConfig): boolean;
|
|
1208
|
+
/**
|
|
1209
|
+
* 输出 deprecation 警告
|
|
1210
|
+
*
|
|
1211
|
+
* @param config - HTTP 客户端配置
|
|
1212
|
+
*/
|
|
1213
|
+
declare function warnDeprecatedConfig(config: HttpClientConfig): void;
|
|
1214
|
+
//#endregion
|
|
1215
|
+
//#region src/contract/client.types.d.ts
|
|
1216
|
+
/**
|
|
1217
|
+
* HTTP 客户端接口
|
|
1218
|
+
*
|
|
1219
|
+
* 定义统一的 HTTP 请求接口,各运行时适配器需实现此接口。
|
|
1220
|
+
* 通过 request 方法基于路由定义实现类型安全的请求。
|
|
1221
|
+
*/
|
|
1222
|
+
type HttpClient = {
|
|
1223
|
+
/**
|
|
1224
|
+
* 发送类型安全的 HTTP 请求
|
|
1225
|
+
*
|
|
1226
|
+
* 基于路由定义自动推断参数和响应类型
|
|
1227
|
+
*
|
|
1228
|
+
* @typeParam TRoute - 路由定义类型
|
|
1229
|
+
* @param options - 请求选项
|
|
1230
|
+
* @returns API 响应
|
|
1231
|
+
*/
|
|
1232
|
+
request<TRoute extends RouteDefinition>(options: {
|
|
1233
|
+
/**
|
|
1234
|
+
* 路由定义
|
|
1235
|
+
*/
|
|
1236
|
+
route: TRoute;
|
|
1237
|
+
/**
|
|
1238
|
+
* 路径参数
|
|
1239
|
+
*/
|
|
1240
|
+
params?: InferRouteParams<TRoute>;
|
|
1241
|
+
/**
|
|
1242
|
+
* 查询参数
|
|
1243
|
+
*/
|
|
1244
|
+
query?: InferRouteQuery<TRoute>;
|
|
1245
|
+
/**
|
|
1246
|
+
* 请求体
|
|
1247
|
+
*/
|
|
1248
|
+
body?: InferRouteBody<TRoute>;
|
|
1249
|
+
/**
|
|
1250
|
+
* 请求配置
|
|
1251
|
+
*/
|
|
1252
|
+
config?: RequestConfig;
|
|
1253
|
+
}): Promise<ApiResponse<InferRouteResponse<TRoute>>>;
|
|
1254
|
+
};
|
|
1255
|
+
/**
|
|
1256
|
+
* 令牌提供者接口
|
|
1257
|
+
*
|
|
1258
|
+
* 定义认证令牌的获取、设置和移除操作。
|
|
1259
|
+
* 仅 getToken 为必需方法,其余为可选。
|
|
1260
|
+
*/
|
|
1261
|
+
type TokenProvider = {
|
|
1262
|
+
/**
|
|
1263
|
+
* 获取当前认证令牌
|
|
1264
|
+
*/
|
|
1265
|
+
getToken(): string | null | Promise<string | null>;
|
|
1266
|
+
/**
|
|
1267
|
+
* 设置认证令牌(可选)
|
|
1268
|
+
*/
|
|
1269
|
+
setToken?(token: string): void | Promise<void>;
|
|
1270
|
+
/**
|
|
1271
|
+
* 移除认证令牌(可选)
|
|
1272
|
+
*/
|
|
1273
|
+
removeToken?(): void | Promise<void>;
|
|
1274
|
+
/**
|
|
1275
|
+
* 获取刷新令牌(可选)
|
|
1276
|
+
*/
|
|
1277
|
+
getRefreshToken?(): string | null | Promise<string | null>;
|
|
1278
|
+
/**
|
|
1279
|
+
* 设置刷新令牌(可选)
|
|
1280
|
+
*/
|
|
1281
|
+
setRefreshToken?(token: string): void | Promise<void>;
|
|
1282
|
+
};
|
|
1283
|
+
/**
|
|
1284
|
+
* 响应转换器类型
|
|
1285
|
+
*
|
|
1286
|
+
* 将非标准后端响应格式转换为 ApiResponse 格式。
|
|
1287
|
+
* 当后端返回的响应格式与 ApiResponse 不同时,
|
|
1288
|
+
* 可通过此转换器在客户端统一转换。
|
|
1289
|
+
*
|
|
1290
|
+
* @deprecated 使用 createResponseTransformerInterceptor 替代
|
|
1291
|
+
* @param raw - 后端原始响应数据
|
|
1292
|
+
* @returns 转换后的 API 响应
|
|
1293
|
+
*/
|
|
1294
|
+
type ResponseTransformer = (raw: unknown) => ApiResponse<unknown>;
|
|
1295
|
+
/**
|
|
1296
|
+
* 认证策略类型
|
|
1297
|
+
*
|
|
1298
|
+
* 支持多种认证方式的联合类型,根据 type 字段区分策略:
|
|
1299
|
+
* - bearer:Bearer Token 认证,使用 tokenProvider 获取令牌
|
|
1300
|
+
* - cookie:Cookie/Session 认证,自动携带凭证
|
|
1301
|
+
* - custom:自定义认证,通过 injector 注入认证信息
|
|
1302
|
+
* - none:无认证,不注入任何认证信息
|
|
1303
|
+
*
|
|
1304
|
+
* @deprecated 使用 createAuthStrategyInterceptor 替代
|
|
1305
|
+
*/
|
|
1306
|
+
type AuthStrategy = {
|
|
1307
|
+
/**
|
|
1308
|
+
* Bearer Token 认证策略
|
|
1309
|
+
*/
|
|
1310
|
+
type: 'bearer';
|
|
1311
|
+
/**
|
|
1312
|
+
* 令牌提供者实例
|
|
1313
|
+
*/
|
|
1314
|
+
tokenProvider: TokenProvider;
|
|
1315
|
+
} | {
|
|
1316
|
+
/**
|
|
1317
|
+
* Cookie/Session 认证策略
|
|
1318
|
+
*/
|
|
1319
|
+
type: 'cookie';
|
|
1320
|
+
/**
|
|
1321
|
+
* 请求凭证模式,默认 'include'
|
|
1322
|
+
*/
|
|
1323
|
+
credentials?: 'include' | 'same-origin' | 'omit';
|
|
1324
|
+
} | {
|
|
1325
|
+
/**
|
|
1326
|
+
* 自定义认证策略
|
|
1327
|
+
*/
|
|
1328
|
+
type: 'custom';
|
|
1329
|
+
/**
|
|
1330
|
+
* 自定义认证注入器,接收请求配置并返回修改后的配置
|
|
1331
|
+
*/
|
|
1332
|
+
injector: (config: Record<string, unknown>) => Record<string, unknown>;
|
|
1333
|
+
} | {
|
|
1334
|
+
/**
|
|
1335
|
+
* 无认证策略
|
|
1336
|
+
*/
|
|
1337
|
+
type: 'none';
|
|
1338
|
+
};
|
|
1339
|
+
/**
|
|
1340
|
+
* CSRF 令牌提供者接口
|
|
1341
|
+
*
|
|
1342
|
+
* 定义 CSRF 令牌的获取操作,用于防止跨站请求伪造攻击
|
|
1343
|
+
*
|
|
1344
|
+
* @deprecated 使用 createCsrfInterceptor 替代
|
|
1345
|
+
*/
|
|
1346
|
+
type CsrfProvider = {
|
|
1347
|
+
/**
|
|
1348
|
+
* 获取 CSRF 令牌
|
|
1349
|
+
*/
|
|
1350
|
+
getToken(): string | null | Promise<string | null>;
|
|
1351
|
+
};
|
|
1352
|
+
/**
|
|
1353
|
+
* HTTP 客户端配置类型
|
|
1354
|
+
*
|
|
1355
|
+
* 创建 HTTP 客户端实例时所需的配置。
|
|
1356
|
+
* 推荐使用拦截器模式进行扩展,旧配置项已标记为 deprecated。
|
|
1357
|
+
*/
|
|
1358
|
+
type HttpClientConfig = {
|
|
1359
|
+
/**
|
|
1360
|
+
* API 基础 URL
|
|
1361
|
+
*/
|
|
1362
|
+
baseUrl: string;
|
|
1363
|
+
/**
|
|
1364
|
+
* 请求超时时间(毫秒)
|
|
1365
|
+
*/
|
|
1366
|
+
timeout?: number;
|
|
1367
|
+
/**
|
|
1368
|
+
* 自定义请求头
|
|
1369
|
+
*/
|
|
1370
|
+
headers?: Record<string, string>;
|
|
1371
|
+
/**
|
|
1372
|
+
* 请求拦截器列表
|
|
1373
|
+
*
|
|
1374
|
+
* 按注册顺序执行,用于在请求发送前修改请求配置
|
|
1375
|
+
*/
|
|
1376
|
+
requestInterceptors?: RequestInterceptor[];
|
|
1377
|
+
/**
|
|
1378
|
+
* 响应拦截器列表
|
|
1379
|
+
*
|
|
1380
|
+
* 按注册顺序执行,用于在响应接收后修改响应数据
|
|
1381
|
+
*/
|
|
1382
|
+
responseInterceptors?: ResponseInterceptor[];
|
|
1383
|
+
/**
|
|
1384
|
+
* 未授权回调
|
|
1385
|
+
*
|
|
1386
|
+
* 当收到 401 响应且所有拦截器都无法恢复时触发
|
|
1387
|
+
*/
|
|
1388
|
+
onUnauthorized?: () => void | Promise<void>;
|
|
1389
|
+
/**
|
|
1390
|
+
* 令牌提供者实例
|
|
1391
|
+
*
|
|
1392
|
+
* @deprecated 使用 requestInterceptors + createAuthTokenInterceptor 替代
|
|
1393
|
+
* 内部自动转换为 auth 拦截器
|
|
1394
|
+
*/
|
|
1395
|
+
tokenProvider?: TokenProvider;
|
|
1396
|
+
/**
|
|
1397
|
+
* 认证策略
|
|
1398
|
+
*
|
|
1399
|
+
* @deprecated 使用 requestInterceptors + createAuthStrategyInterceptor 替代
|
|
1400
|
+
* 内部自动转换为对应的 auth 拦截器
|
|
1401
|
+
*/
|
|
1402
|
+
authStrategy?: AuthStrategy;
|
|
1403
|
+
/**
|
|
1404
|
+
* 响应转换器
|
|
1405
|
+
*
|
|
1406
|
+
* @deprecated 使用 responseInterceptors + createResponseTransformerInterceptor 替代
|
|
1407
|
+
* 内部自动转换为响应拦截器
|
|
1408
|
+
*/
|
|
1409
|
+
responseTransformer?: ResponseTransformer;
|
|
1410
|
+
/**
|
|
1411
|
+
* CSRF 令牌提供者
|
|
1412
|
+
*
|
|
1413
|
+
* @deprecated 使用 requestInterceptors + createCsrfInterceptor 替代
|
|
1414
|
+
* 内部自动转换为 CSRF 拦截器
|
|
1415
|
+
*/
|
|
1416
|
+
csrfProvider?: CsrfProvider;
|
|
1417
|
+
/**
|
|
1418
|
+
* CSRF 请求头名称
|
|
1419
|
+
*
|
|
1420
|
+
* @deprecated 在 createCsrfInterceptor 中配置
|
|
1421
|
+
*/
|
|
1422
|
+
csrfHeaderName?: string;
|
|
1423
|
+
/**
|
|
1424
|
+
* 响应验证配置
|
|
1425
|
+
*
|
|
1426
|
+
* 启用后对响应数据执行 Zod Schema 验证(safeParse),
|
|
1427
|
+
* 默认在开发环境以 warn 模式运行。
|
|
1428
|
+
*
|
|
1429
|
+
* - 传入配置对象自定义验证行为
|
|
1430
|
+
* - 传入 false 显式禁用验证
|
|
1431
|
+
* - 不传则使用默认值(开发环境 warn)
|
|
1432
|
+
*/
|
|
1433
|
+
validation?: ValidationInterceptorConfig | false;
|
|
1434
|
+
};
|
|
1435
|
+
//#endregion
|
|
1436
|
+
//#region src/schemas/common.schema.d.ts
|
|
1437
|
+
/**
|
|
1438
|
+
* ID 参数 Schema
|
|
1439
|
+
*
|
|
1440
|
+
* 用于需要单个 ID 的接口,如详情查询、删除等
|
|
1441
|
+
*/
|
|
1442
|
+
declare const IdParamsSchema: z.ZodObject<{
|
|
1443
|
+
id: z.ZodString;
|
|
1444
|
+
}, z.core.$strip>;
|
|
1445
|
+
/**
|
|
1446
|
+
* ID 参数类型
|
|
1447
|
+
*/
|
|
1448
|
+
type IdParams = z.infer<typeof IdParamsSchema>;
|
|
1449
|
+
/**
|
|
1450
|
+
* 分页查询参数 Schema
|
|
1451
|
+
*
|
|
1452
|
+
* 基于 @longzai-intelligence/pagination 的 PaginationParamsSchema 扩展,
|
|
1453
|
+
* 添加 z.coerce 支持 HTTP query string 自动类型转换,以及默认值和最大值限制
|
|
1454
|
+
*
|
|
1455
|
+
* 默认值与 @longzai-intelligence/pagination 的 PAGINATION_DEFAULTS 保持一致
|
|
1456
|
+
*/
|
|
1457
|
+
declare const PaginationQuerySchema: z.ZodObject<{
|
|
1458
|
+
page: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
1459
|
+
pageSize: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
1460
|
+
}, z.core.$strip>;
|
|
1461
|
+
/**
|
|
1462
|
+
* 分页查询参数类型
|
|
1463
|
+
*/
|
|
1464
|
+
type PaginationQuery = z.infer<typeof PaginationQuerySchema>;
|
|
1465
|
+
/**
|
|
1466
|
+
* HTTP 分页查询参数配置类型
|
|
1467
|
+
*
|
|
1468
|
+
* 用于 createHttpPaginationSchema 工厂函数的自定义配置,
|
|
1469
|
+
* 支持不同后端使用不同的分页字段名
|
|
1470
|
+
*
|
|
1471
|
+
* 配置项与 @longzai-intelligence/pagination 的 createPaginationDefaults 对齐
|
|
1472
|
+
*/
|
|
1473
|
+
type HttpPaginationConfig = {
|
|
1474
|
+
/**
|
|
1475
|
+
* 每页条数字段名,默认 'pageSize'
|
|
1476
|
+
*/
|
|
1477
|
+
pageSizeField?: string;
|
|
1478
|
+
/**
|
|
1479
|
+
* 默认页码,默认使用 PAGINATION_DEFAULTS.page
|
|
1480
|
+
*/
|
|
1481
|
+
defaultPage?: number;
|
|
1482
|
+
/**
|
|
1483
|
+
* 默认每页条数,默认使用 PAGINATION_DEFAULTS.pageSize
|
|
1484
|
+
*/
|
|
1485
|
+
defaultPageSize?: number;
|
|
1486
|
+
/**
|
|
1487
|
+
* 每页最大条数,默认使用 PAGINATION_DEFAULTS.maxPageSize
|
|
1488
|
+
*/
|
|
1489
|
+
maxPageSize?: number;
|
|
1490
|
+
/**
|
|
1491
|
+
* 每页最小条数,默认使用 PAGINATION_DEFAULTS.minPageSize
|
|
1492
|
+
*/
|
|
1493
|
+
minPageSize?: number;
|
|
1494
|
+
};
|
|
1495
|
+
/**
|
|
1496
|
+
* 创建 HTTP 分页查询参数 Schema 的工厂函数
|
|
1497
|
+
*
|
|
1498
|
+
* 根据 @longzai-intelligence/pagination 的 createPaginationSchema 和 createPaginationDefaults,
|
|
1499
|
+
* 添加 HTTP 传输层特有的 z.coerce 支持。
|
|
1500
|
+
*
|
|
1501
|
+
* @example
|
|
1502
|
+
* const schema = createHttpPaginationSchema();
|
|
1503
|
+
* // 生成 { page?: number, pageSize?: number } Schema,带 z.coerce 和默认值
|
|
1504
|
+
*
|
|
1505
|
+
* @example
|
|
1506
|
+
* const schema = createHttpPaginationSchema({ pageSizeField: 'limit' });
|
|
1507
|
+
* // 生成 { page?: number, limit?: number } Schema
|
|
1508
|
+
*
|
|
1509
|
+
* @param config - HTTP 分页查询参数配置,可选
|
|
1510
|
+
* @returns 分页查询参数 Zod Schema
|
|
1511
|
+
*/
|
|
1512
|
+
declare function createHttpPaginationSchema(config?: HttpPaginationConfig): z.ZodObject<{
|
|
1513
|
+
[x: string]: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
1514
|
+
page: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
1515
|
+
}, z.core.$strip>;
|
|
1516
|
+
/**
|
|
1517
|
+
* 过滤查询参数 Schema
|
|
1518
|
+
*
|
|
1519
|
+
* 用于列表接口的过滤和排序
|
|
1520
|
+
* 排序参数使用 @longzai-intelligence/pagination 的 SortParamsSchema
|
|
1521
|
+
*/
|
|
1522
|
+
declare const FilterQuerySchema: z.ZodObject<{
|
|
1523
|
+
filter: z.ZodOptional<z.ZodString>;
|
|
1524
|
+
sortBy: z.ZodOptional<z.ZodString>;
|
|
1525
|
+
sortOrder: z.ZodOptional<z.ZodEnum<{
|
|
1526
|
+
asc: "asc";
|
|
1527
|
+
desc: "desc";
|
|
1528
|
+
}>>;
|
|
1529
|
+
}, z.core.$strip>;
|
|
1530
|
+
/**
|
|
1531
|
+
* 过滤查询参数类型
|
|
1532
|
+
*/
|
|
1533
|
+
type FilterQuery = z.infer<typeof FilterQuerySchema>;
|
|
1534
|
+
/**
|
|
1535
|
+
* 创建带排序字段约束的过滤查询参数 Schema
|
|
1536
|
+
*
|
|
1537
|
+
* @example
|
|
1538
|
+
* const schema = createFilterQuerySchema(['name', 'createdAt'] as const);
|
|
1539
|
+
* // sortBy 只能为 'name' | 'createdAt'
|
|
1540
|
+
*
|
|
1541
|
+
* @typeParam T - 排序字段元组类型
|
|
1542
|
+
* @param sortFields - 允许排序的字段名称数组
|
|
1543
|
+
* @returns 过滤查询参数 Zod Schema
|
|
1544
|
+
*/
|
|
1545
|
+
declare function createFilterQuerySchema<T extends [string, ...string[]]>(sortFields: T): z.ZodObject<{
|
|
1546
|
+
filter: z.ZodOptional<z.ZodString>;
|
|
1547
|
+
sortBy: z.ZodOptional<z.ZodEnum<{ [k_1 in T[number]]: k_1 } extends infer T_1 ? { [k in keyof T_1]: T_1[k] } : never>>;
|
|
1548
|
+
sortOrder: z.ZodOptional<z.ZodEnum<{
|
|
1549
|
+
asc: "asc";
|
|
1550
|
+
desc: "desc";
|
|
1551
|
+
}>>;
|
|
1552
|
+
}, z.core.$strip>;
|
|
1553
|
+
/**
|
|
1554
|
+
* 日期范围查询参数 Schema
|
|
1555
|
+
*
|
|
1556
|
+
* 用于按日期范围筛选的接口
|
|
1557
|
+
*/
|
|
1558
|
+
declare const DateRangeQuerySchema: z.ZodObject<{
|
|
1559
|
+
startDate: z.ZodOptional<z.ZodString>;
|
|
1560
|
+
endDate: z.ZodOptional<z.ZodString>;
|
|
1561
|
+
}, z.core.$strip>;
|
|
1562
|
+
/**
|
|
1563
|
+
* 日期范围查询参数类型
|
|
1564
|
+
*/
|
|
1565
|
+
type DateRangeQuery = z.infer<typeof DateRangeQuerySchema>;
|
|
1566
|
+
/**
|
|
1567
|
+
* 搜索查询参数 Schema
|
|
1568
|
+
*
|
|
1569
|
+
* 用于关键词搜索的接口
|
|
1570
|
+
*/
|
|
1571
|
+
declare const SearchQuerySchema: z.ZodObject<{
|
|
1572
|
+
keyword: z.ZodOptional<z.ZodString>;
|
|
1573
|
+
}, z.core.$strip>;
|
|
1574
|
+
/**
|
|
1575
|
+
* 搜索查询参数类型
|
|
1576
|
+
*/
|
|
1577
|
+
type SearchQuery = z.infer<typeof SearchQuerySchema>;
|
|
1578
|
+
//#endregion
|
|
1579
|
+
//#region src/schemas/error.schema.d.ts
|
|
1580
|
+
/**
|
|
1581
|
+
* 通用错误码定义
|
|
1582
|
+
*
|
|
1583
|
+
* 仅包含跨项目通用的错误码,业务特定错误码由各项目通过 createErrorCodeSchema 扩展
|
|
1584
|
+
*/
|
|
1585
|
+
declare const ErrorCodeSchema: z.ZodEnum<{
|
|
1586
|
+
UNKNOWN: "UNKNOWN";
|
|
1587
|
+
INVALID_PARAMETER: "INVALID_PARAMETER";
|
|
1588
|
+
RESOURCE_NOT_FOUND: "RESOURCE_NOT_FOUND";
|
|
1589
|
+
RESOURCE_ALREADY_EXISTS: "RESOURCE_ALREADY_EXISTS";
|
|
1590
|
+
OPERATION_FAILED: "OPERATION_FAILED";
|
|
1591
|
+
PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
1592
|
+
UNAUTHORIZED: "UNAUTHORIZED";
|
|
1593
|
+
TOKEN_EXPIRED: "TOKEN_EXPIRED";
|
|
1594
|
+
TOKEN_INVALID: "TOKEN_INVALID";
|
|
1595
|
+
LOGIN_FAILED: "LOGIN_FAILED";
|
|
1596
|
+
ACCOUNT_DISABLED: "ACCOUNT_DISABLED";
|
|
1597
|
+
PASSWORD_INCORRECT: "PASSWORD_INCORRECT";
|
|
1598
|
+
DATABASE_ERROR: "DATABASE_ERROR";
|
|
1599
|
+
EXTERNAL_SERVICE_ERROR: "EXTERNAL_SERVICE_ERROR";
|
|
1600
|
+
RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED";
|
|
1601
|
+
DUPLICATE_REQUEST: "DUPLICATE_REQUEST";
|
|
1602
|
+
VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
1603
|
+
}>;
|
|
1604
|
+
/**
|
|
1605
|
+
* 通用错误码类型
|
|
1606
|
+
*/
|
|
1607
|
+
type ErrorCode = z.infer<typeof ErrorCodeSchema>;
|
|
1608
|
+
/**
|
|
1609
|
+
* 通用错误码对应的错误消息
|
|
1610
|
+
*/
|
|
1611
|
+
declare const ERROR_MESSAGES: Record<ErrorCode, string>;
|
|
1612
|
+
/**
|
|
1613
|
+
* 获取错误码对应的错误消息
|
|
1614
|
+
*
|
|
1615
|
+
* @param code - 错误码
|
|
1616
|
+
* @returns 错误消息字符串
|
|
1617
|
+
*/
|
|
1618
|
+
declare function getErrorMessage(code: ErrorCode): string;
|
|
1619
|
+
/**
|
|
1620
|
+
* 通用错误码到 HTTP 状态码的映射
|
|
1621
|
+
*/
|
|
1622
|
+
declare const ERROR_HTTP_STATUS: Partial<Record<ErrorCode, number>>;
|
|
1623
|
+
/**
|
|
1624
|
+
* 获取错误码对应的 HTTP 状态码
|
|
1625
|
+
*
|
|
1626
|
+
* @param code - 错误码
|
|
1627
|
+
* @returns HTTP 状态码,默认 400
|
|
1628
|
+
*/
|
|
1629
|
+
declare function getHttpStatus(code: ErrorCode): number;
|
|
1630
|
+
/**
|
|
1631
|
+
* 创建业务错误码 Schema 的工厂函数
|
|
1632
|
+
*
|
|
1633
|
+
* 在通用错误码基础上扩展项目特定的业务错误码
|
|
1634
|
+
*
|
|
1635
|
+
* @example
|
|
1636
|
+
* const KtvErrorCodeSchema = createErrorCodeSchema(
|
|
1637
|
+
* ['ORDER_NOT_FOUND', 'ROOM_NOT_AVAILABLE'] as const,
|
|
1638
|
+
* 'KTV 错误码',
|
|
1639
|
+
* );
|
|
1640
|
+
*
|
|
1641
|
+
* @typeParam T - 业务错误码数组类型
|
|
1642
|
+
* @param businessCodes - 业务特定的错误码数组
|
|
1643
|
+
* @param description - Schema 描述
|
|
1644
|
+
* @returns 包含通用和业务错误码的枚举定义
|
|
1645
|
+
* @throws {@link Error} 当错误码合并失败时抛出错误
|
|
1646
|
+
*/
|
|
1647
|
+
declare function createErrorCodeSchema<T extends readonly string[]>(businessCodes: T, description?: string): z.ZodEnum<{ [k_1 in "UNKNOWN" | "INVALID_PARAMETER" | "RESOURCE_NOT_FOUND" | "RESOURCE_ALREADY_EXISTS" | "OPERATION_FAILED" | "PERMISSION_DENIED" | "UNAUTHORIZED" | "TOKEN_EXPIRED" | "TOKEN_INVALID" | "LOGIN_FAILED" | "ACCOUNT_DISABLED" | "PASSWORD_INCORRECT" | "DATABASE_ERROR" | "EXTERNAL_SERVICE_ERROR" | "RATE_LIMIT_EXCEEDED" | "DUPLICATE_REQUEST" | "VALIDATION_ERROR" | T[number]]: k_1 } extends infer T_1 ? { [k in keyof T_1]: T_1[k] } : never>;
|
|
1648
|
+
/**
|
|
1649
|
+
* 错误码配置类型
|
|
1650
|
+
*
|
|
1651
|
+
* 用于 createErrorCodeSchema 配置业务错误码
|
|
1652
|
+
*
|
|
1653
|
+
* @typeParam T - 业务错误码数组类型
|
|
1654
|
+
*/
|
|
1655
|
+
type ErrorCodeConfig<T extends readonly string[]> = {
|
|
1656
|
+
/**
|
|
1657
|
+
* 业务特定的错误码数组
|
|
1658
|
+
*/
|
|
1659
|
+
codes: T;
|
|
1660
|
+
/**
|
|
1661
|
+
* Schema 描述
|
|
1662
|
+
*/
|
|
1663
|
+
description?: string;
|
|
1664
|
+
};
|
|
1665
|
+
/**
|
|
1666
|
+
* API 错误响应 Schema
|
|
1667
|
+
*/
|
|
1668
|
+
declare const ApiErrorResponseSchema: z.ZodObject<{
|
|
1669
|
+
code: z.ZodEnum<{
|
|
1670
|
+
UNKNOWN: "UNKNOWN";
|
|
1671
|
+
INVALID_PARAMETER: "INVALID_PARAMETER";
|
|
1672
|
+
RESOURCE_NOT_FOUND: "RESOURCE_NOT_FOUND";
|
|
1673
|
+
RESOURCE_ALREADY_EXISTS: "RESOURCE_ALREADY_EXISTS";
|
|
1674
|
+
OPERATION_FAILED: "OPERATION_FAILED";
|
|
1675
|
+
PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
1676
|
+
UNAUTHORIZED: "UNAUTHORIZED";
|
|
1677
|
+
TOKEN_EXPIRED: "TOKEN_EXPIRED";
|
|
1678
|
+
TOKEN_INVALID: "TOKEN_INVALID";
|
|
1679
|
+
LOGIN_FAILED: "LOGIN_FAILED";
|
|
1680
|
+
ACCOUNT_DISABLED: "ACCOUNT_DISABLED";
|
|
1681
|
+
PASSWORD_INCORRECT: "PASSWORD_INCORRECT";
|
|
1682
|
+
DATABASE_ERROR: "DATABASE_ERROR";
|
|
1683
|
+
EXTERNAL_SERVICE_ERROR: "EXTERNAL_SERVICE_ERROR";
|
|
1684
|
+
RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED";
|
|
1685
|
+
DUPLICATE_REQUEST: "DUPLICATE_REQUEST";
|
|
1686
|
+
VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
1687
|
+
}>;
|
|
1688
|
+
message: z.ZodString;
|
|
1689
|
+
data: z.ZodNullable<z.ZodUnknown>;
|
|
1690
|
+
}, z.core.$strip>;
|
|
1691
|
+
/**
|
|
1692
|
+
* API 错误响应类型
|
|
1693
|
+
*/
|
|
1694
|
+
type ApiErrorResponse = z.infer<typeof ApiErrorResponseSchema>;
|
|
1695
|
+
//#endregion
|
|
1696
|
+
//#region src/routes/utils.d.ts
|
|
1697
|
+
/**
|
|
1698
|
+
* 定义 API 路由
|
|
1699
|
+
*
|
|
1700
|
+
* 创建类型安全的路由定义,所有泛型参数从配置对象自动推断
|
|
1701
|
+
*
|
|
1702
|
+
* @example
|
|
1703
|
+
* const loginRoute = defineRoute({
|
|
1704
|
+
* method: 'POST',
|
|
1705
|
+
* path: '/v1/auth/login',
|
|
1706
|
+
* body: LoginBodySchema,
|
|
1707
|
+
* response: ApiResponseSchema(AuthResponseSchema),
|
|
1708
|
+
* summary: '用户登录',
|
|
1709
|
+
* tags: ['认证'],
|
|
1710
|
+
* });
|
|
1711
|
+
*
|
|
1712
|
+
* @typeParam TMethod - HTTP 方法类型
|
|
1713
|
+
* @typeParam TPath - 路径模板字符串
|
|
1714
|
+
* @typeParam TParams - 路径参数 Zod Schema
|
|
1715
|
+
* @typeParam TQuery - 查询参数 Zod Schema
|
|
1716
|
+
* @typeParam TBody - 请求体 Zod Schema
|
|
1717
|
+
* @typeParam TResponse - 响应 Zod Schema
|
|
1718
|
+
* @param config - 路由配置对象
|
|
1719
|
+
* @returns 类型安全的路由定义
|
|
1720
|
+
*/
|
|
1721
|
+
/**
|
|
1722
|
+
* 定义 API 路由配置类型
|
|
1723
|
+
*
|
|
1724
|
+
* 描述 defineRoute 函数的配置参数结构
|
|
1725
|
+
*
|
|
1726
|
+
* @typeParam TMethod - HTTP 方法类型
|
|
1727
|
+
* @typeParam TPath - 路径模板字符串
|
|
1728
|
+
* @typeParam TParams - 路径参数 Schema 类型
|
|
1729
|
+
* @typeParam TQuery - 查询参数 Schema 类型
|
|
1730
|
+
* @typeParam TBody - 请求体 Schema 类型
|
|
1731
|
+
* @typeParam TResponse - 响应 Schema 类型
|
|
1732
|
+
*/
|
|
1733
|
+
type DefineRouteConfig<TMethod extends HttpMethod, TPath extends string, TParams extends ZodType | undefined, TQuery extends ZodType | undefined, TBody extends ZodType | undefined, TResponse extends ZodType> = {
|
|
1734
|
+
/**
|
|
1735
|
+
* HTTP 请求方法
|
|
1736
|
+
*/
|
|
1737
|
+
method: TMethod;
|
|
1738
|
+
/**
|
|
1739
|
+
* API 路径模板
|
|
1740
|
+
*/
|
|
1741
|
+
path: TPath;
|
|
1742
|
+
/**
|
|
1743
|
+
* 路径参数 Schema
|
|
1744
|
+
*/
|
|
1745
|
+
params?: TParams;
|
|
1746
|
+
/**
|
|
1747
|
+
* 查询参数 Schema
|
|
1748
|
+
*/
|
|
1749
|
+
query?: TQuery;
|
|
1750
|
+
/**
|
|
1751
|
+
* 请求体 Schema
|
|
1752
|
+
*/
|
|
1753
|
+
body?: TBody;
|
|
1754
|
+
/**
|
|
1755
|
+
* 响应 Schema
|
|
1756
|
+
*/
|
|
1757
|
+
response: TResponse;
|
|
1758
|
+
/**
|
|
1759
|
+
* 接口描述信息
|
|
1760
|
+
*/
|
|
1761
|
+
summary?: string;
|
|
1762
|
+
/**
|
|
1763
|
+
* 接口标签
|
|
1764
|
+
*/
|
|
1765
|
+
tags?: string[];
|
|
1766
|
+
};
|
|
1767
|
+
/**
|
|
1768
|
+
* 定义 API 路由
|
|
1769
|
+
*
|
|
1770
|
+
* 创建类型安全的路由定义,所有泛型参数从配置对象自动推断
|
|
1771
|
+
*
|
|
1772
|
+
* @example
|
|
1773
|
+
* const loginRoute = defineRoute({
|
|
1774
|
+
* method: 'POST',
|
|
1775
|
+
* path: '/v1/auth/login',
|
|
1776
|
+
* body: LoginBodySchema,
|
|
1777
|
+
* response: ApiResponseSchema(AuthResponseSchema),
|
|
1778
|
+
* summary: '用户登录',
|
|
1779
|
+
* tags: ['认证'],
|
|
1780
|
+
* });
|
|
1781
|
+
*
|
|
1782
|
+
* @typeParam TMethod - HTTP 方法类型
|
|
1783
|
+
* @typeParam TPath - 路径模板字符串
|
|
1784
|
+
* @typeParam TParams - 路径参数 Schema 类型
|
|
1785
|
+
* @typeParam TQuery - 查询参数 Schema 类型
|
|
1786
|
+
* @typeParam TBody - 请求体 Schema 类型
|
|
1787
|
+
* @typeParam TResponse - 响应 Schema 类型
|
|
1788
|
+
* @param config - 路由配置对象
|
|
1789
|
+
* @returns 类型安全的路由定义
|
|
1790
|
+
* @throws {@link Error} 当路由定义创建失败时抛出错误
|
|
1791
|
+
*/
|
|
1792
|
+
declare function defineRoute<TMethod extends HttpMethod, TPath extends string, TParams extends ZodType | undefined, TQuery extends ZodType | undefined, TBody extends ZodType | undefined, TResponse extends ZodType>(config: DefineRouteConfig<TMethod, TPath, TParams, TQuery, TBody, TResponse>): RouteDefinition<TMethod, TPath, TParams, TQuery, TBody, TResponse>;
|
|
1793
|
+
/**
|
|
1794
|
+
* 构建完整 URL 路径
|
|
1795
|
+
*
|
|
1796
|
+
* 将路径模板中的 :param 替换为实际值,并附加查询参数
|
|
1797
|
+
*
|
|
1798
|
+
* @example
|
|
1799
|
+
* buildPath('/v1/users/:id', { id: '123' }, { include: 'profile' });
|
|
1800
|
+
* // '/v1/users/123?include=profile'
|
|
1801
|
+
*
|
|
1802
|
+
* @param path - 路径模板,如 /v1/users/:id
|
|
1803
|
+
* @param params - 路径参数键值对
|
|
1804
|
+
* @param query - 查询参数键值对,undefined 值会被忽略
|
|
1805
|
+
* @returns 完整的 URL 路径
|
|
1806
|
+
*/
|
|
1807
|
+
declare function buildPath(path: string, params?: Record<string, string | number>, query?: Record<string, string | number | boolean | undefined>): string;
|
|
1808
|
+
/**
|
|
1809
|
+
* 构建查询字符串
|
|
1810
|
+
*
|
|
1811
|
+
* 将查询参数对象转换为 URL 查询字符串,undefined 值会被忽略
|
|
1812
|
+
*
|
|
1813
|
+
* @example
|
|
1814
|
+
* buildQuery({ page: 1, pageSize: 10 });
|
|
1815
|
+
* // '?page=1&pageSize=10'
|
|
1816
|
+
*
|
|
1817
|
+
* @param query - 查询参数键值对
|
|
1818
|
+
* @returns 查询字符串,以 ? 开头;无参数时返回空字符串
|
|
1819
|
+
*/
|
|
1820
|
+
declare function buildQuery(query?: Record<string, string | number | boolean | undefined>): string;
|
|
1821
|
+
/**
|
|
1822
|
+
* 拼接路径片段
|
|
1823
|
+
*
|
|
1824
|
+
* 将两个路径字符串拼接为一个完整路径,返回类型安全的模板字面量类型
|
|
1825
|
+
*
|
|
1826
|
+
* @typeParam T - 前缀路径类型
|
|
1827
|
+
* @typeParam U - 子路径类型
|
|
1828
|
+
* @param a - 前缀路径
|
|
1829
|
+
* @param b - 子路径
|
|
1830
|
+
* @returns 拼接后的完整路径
|
|
1831
|
+
*/
|
|
1832
|
+
declare function concatPath<T extends string, U extends string>(a: T, b: U): `${T}${U}`;
|
|
1833
|
+
//#endregion
|
|
1834
|
+
//#region src/routes/route-group.utils.d.ts
|
|
1835
|
+
/**
|
|
1836
|
+
* API 版本号类型
|
|
1837
|
+
*
|
|
1838
|
+
* 支持标准版本格式:v1, v2, v3, ...
|
|
1839
|
+
* 也支持自定义版本字符串
|
|
1840
|
+
*/
|
|
1841
|
+
type ApiVersion = `v${number}` | (string & {});
|
|
1842
|
+
/**
|
|
1843
|
+
* 默认认证策略类型
|
|
1844
|
+
*
|
|
1845
|
+
* 支持三种内置策略和自定义字符串策略
|
|
1846
|
+
*/
|
|
1847
|
+
type DefaultAuthStrategy = 'public' | 'user' | 'admin' | (string & {});
|
|
1848
|
+
/**
|
|
1849
|
+
* 计算带版本前缀的完整路径类型
|
|
1850
|
+
*
|
|
1851
|
+
* @typeParam TVersion - 版本号类型
|
|
1852
|
+
* @typeParam TPrefix - 路径前缀类型
|
|
1853
|
+
*/
|
|
1854
|
+
type VersionedPrefix<TVersion extends ApiVersion | undefined, TPrefix extends string> = TVersion extends ApiVersion ? TPrefix extends `/${string}` ? `/${TVersion}${TPrefix}` : TPrefix extends '' ? `/${TVersion}` : `/${TVersion}/${TPrefix}` : TPrefix;
|
|
1855
|
+
/**
|
|
1856
|
+
* 路由分组配置
|
|
1857
|
+
*
|
|
1858
|
+
* @typeParam TPrefix - 路径前缀类型
|
|
1859
|
+
* @typeParam TVersion - API 版本号类型
|
|
1860
|
+
* @typeParam TAuthStrategy - 认证策略类型
|
|
1861
|
+
*/
|
|
1862
|
+
type RouteGroupConfig<TPrefix extends string = '', TVersion extends ApiVersion | undefined = undefined, TAuthStrategy extends string = DefaultAuthStrategy> = {
|
|
1863
|
+
/**
|
|
1864
|
+
* 父路由分组(可选)
|
|
1865
|
+
*
|
|
1866
|
+
* 指定父分组时,当前分组会继承父分组的配置并追加路径
|
|
1867
|
+
* - prefix 会追加到父分组的 prefix 后面
|
|
1868
|
+
* - auth 和 tags 会继承父分组的值(如果未指定)
|
|
1869
|
+
*/
|
|
1870
|
+
parent?: RouteGroup<string, ApiVersion | undefined, TAuthStrategy>;
|
|
1871
|
+
/**
|
|
1872
|
+
* 路径前缀(可选)
|
|
1873
|
+
*
|
|
1874
|
+
* 所有子路由的路径都会自动拼接此前缀
|
|
1875
|
+
* 如果指定了 parent,此前缀会追加到父分组的 prefix 后面
|
|
1876
|
+
* 如果指定了 version,版本前缀会自动添加到 prefix 前面
|
|
1877
|
+
* 如果未指定,默认为空字符串
|
|
1878
|
+
*/
|
|
1879
|
+
prefix?: TPrefix;
|
|
1880
|
+
/**
|
|
1881
|
+
* API 版本号
|
|
1882
|
+
*
|
|
1883
|
+
* 版本前缀会自动添加到 prefix 前面,格式为 /{version}
|
|
1884
|
+
* 例如:version: 'v1', prefix: 'client' -> 实际前缀: /v1/client
|
|
1885
|
+
* 例如:version: 'v1', prefix: '' -> 实际前缀: /v1
|
|
1886
|
+
*
|
|
1887
|
+
* 注意:如果指定了 parent,version 应该在父分组中指定,子分组会自动继承
|
|
1888
|
+
*/
|
|
1889
|
+
version?: TVersion;
|
|
1890
|
+
/**
|
|
1891
|
+
* 认证策略
|
|
1892
|
+
*
|
|
1893
|
+
* 标识分组内路由的认证要求,可由适配器读取并应用相应的中间件
|
|
1894
|
+
* 如果指定了 parent 且未设置此字段,会继承父分组的 auth
|
|
1895
|
+
*/
|
|
1896
|
+
auth?: TAuthStrategy;
|
|
1897
|
+
/**
|
|
1898
|
+
* API 标签(用于 Swagger 分组和 TypedController)
|
|
1899
|
+
*
|
|
1900
|
+
* TypedController 装饰器会使用这些标签设置 @ApiTags()
|
|
1901
|
+
* 子路由会继承这些标签,并可追加自己的标签
|
|
1902
|
+
* 如果指定了 parent 且未设置此字段,会继承父分组的 tags
|
|
1903
|
+
*/
|
|
1904
|
+
tags?: string[];
|
|
1905
|
+
/**
|
|
1906
|
+
* 路由定义集合(可选)
|
|
1907
|
+
*
|
|
1908
|
+
* 提供 routes 时,defineRouteGroup 返回 RouteGroup & { routes },
|
|
1909
|
+
* 可直接用于 TypedController 和 TypedRoute。
|
|
1910
|
+
* 不提供 routes 时,返回纯 RouteGroup,可用于 defineRoute 拆分定义。
|
|
1911
|
+
*
|
|
1912
|
+
* 接受两种输入:
|
|
1913
|
+
* - 内联原始配置对象(简单场景,少量路由)
|
|
1914
|
+
* - group.defineRoute() 的返回值(复杂场景,拆分定义)
|
|
1915
|
+
*/
|
|
1916
|
+
routes?: Record<string, RouteDefineConfig | ProcessedRoute<RouteDefinition>>;
|
|
1917
|
+
};
|
|
1918
|
+
/**
|
|
1919
|
+
* 路由分组
|
|
1920
|
+
*
|
|
1921
|
+
* 提供路由分组功能,子路由自动继承分组的配置
|
|
1922
|
+
*
|
|
1923
|
+
* @typeParam TPrefix - 路径前缀类型
|
|
1924
|
+
* @typeParam TVersion - API 版本号类型
|
|
1925
|
+
* @typeParam TAuthStrategy - 认证策略类型
|
|
1926
|
+
*/
|
|
1927
|
+
type RouteGroup<TPrefix extends string = string, TVersion extends ApiVersion | undefined = undefined, TAuthStrategy extends string = DefaultAuthStrategy> = {
|
|
1928
|
+
/**
|
|
1929
|
+
* 完整路径前缀(包含版本)
|
|
1930
|
+
*
|
|
1931
|
+
* 如果指定了 version,格式为 /{version}/{prefix}
|
|
1932
|
+
* 如果未指定 version,则为原始 prefix
|
|
1933
|
+
*/
|
|
1934
|
+
readonly prefix: VersionedPrefix<TVersion, TPrefix>;
|
|
1935
|
+
/**
|
|
1936
|
+
* API 版本号
|
|
1937
|
+
*/
|
|
1938
|
+
readonly version?: TVersion;
|
|
1939
|
+
/**
|
|
1940
|
+
* 认证策略
|
|
1941
|
+
*
|
|
1942
|
+
* 标识分组内路由的认证要求
|
|
1943
|
+
*/
|
|
1944
|
+
readonly auth?: TAuthStrategy;
|
|
1945
|
+
/**
|
|
1946
|
+
* API 标签(用于 Swagger 分组和 TypedController)
|
|
1947
|
+
*
|
|
1948
|
+
* 用于接口分组和文档生成
|
|
1949
|
+
*/
|
|
1950
|
+
readonly tags?: string[];
|
|
1951
|
+
/**
|
|
1952
|
+
* 定义单条路由
|
|
1953
|
+
*
|
|
1954
|
+
* 语法糖,用于需要单独引用某条路由或拆分复杂路由定义的场景。
|
|
1955
|
+
* 子路由的路径会自动拼接分组前缀,并继承分组的认证策略和标签。
|
|
1956
|
+
*
|
|
1957
|
+
* @typeParam TMethod - HTTP 方法类型
|
|
1958
|
+
* @typeParam TPath - 路径模板字符串
|
|
1959
|
+
* @typeParam TParams - 路径参数 Zod Schema
|
|
1960
|
+
* @typeParam TQuery - 查询参数 Zod Schema
|
|
1961
|
+
* @typeParam TBody - 请求体 Zod Schema
|
|
1962
|
+
* @typeParam TResponse - 响应 Zod Schema
|
|
1963
|
+
* @param config - 路由配置对象
|
|
1964
|
+
* @returns 类型安全的路由定义,路径已拼接前缀
|
|
1965
|
+
*/
|
|
1966
|
+
defineRoute: <TMethod extends HttpMethod = HttpMethod, TPath extends string = string, TParams extends ZodType | undefined = undefined, TQuery extends ZodType | undefined = undefined, TBody extends ZodType | undefined = undefined, TResponse extends ZodType = ZodType>(config: RouteDefineConfig<TMethod, TPath, TParams, TQuery, TBody, TResponse>) => RouteDefinition<TMethod, `${VersionedPrefix<TVersion, TPrefix>}${TPath}`, TParams, TQuery, TBody, TResponse> & {
|
|
1967
|
+
/**
|
|
1968
|
+
* 认证策略
|
|
1969
|
+
*/
|
|
1970
|
+
auth?: TAuthStrategy;
|
|
1971
|
+
};
|
|
1972
|
+
};
|
|
1973
|
+
/**
|
|
1974
|
+
* 路由定义配置(用于分组内定义)
|
|
1975
|
+
*
|
|
1976
|
+
* @typeParam TMethod - HTTP 方法类型
|
|
1977
|
+
* @typeParam TPath - 路径模板字符串
|
|
1978
|
+
* @typeParam TParams - 路径参数 Schema 类型
|
|
1979
|
+
* @typeParam TQuery - 查询参数 Schema 类型
|
|
1980
|
+
* @typeParam TBody - 请求体 Schema 类型
|
|
1981
|
+
* @typeParam TResponse - 响应 Schema 类型
|
|
1982
|
+
*/
|
|
1983
|
+
type RouteDefineConfig<TMethod extends HttpMethod = HttpMethod, TPath extends string = string, TParams extends ZodType | undefined = ZodType | undefined, TQuery extends ZodType | undefined = ZodType | undefined, TBody extends ZodType | undefined = ZodType | undefined, TResponse extends ZodType = ZodType> = {
|
|
1984
|
+
/**
|
|
1985
|
+
* HTTP 方法
|
|
1986
|
+
*/
|
|
1987
|
+
method: TMethod;
|
|
1988
|
+
/**
|
|
1989
|
+
* 路径模板,会自动拼接分组前缀
|
|
1990
|
+
*/
|
|
1991
|
+
path: TPath;
|
|
1992
|
+
/**
|
|
1993
|
+
* 路径参数 Schema
|
|
1994
|
+
*/
|
|
1995
|
+
params?: TParams;
|
|
1996
|
+
/**
|
|
1997
|
+
* 查询参数 Schema
|
|
1998
|
+
*/
|
|
1999
|
+
query?: TQuery;
|
|
2000
|
+
/**
|
|
2001
|
+
* 请求体 Schema
|
|
2002
|
+
*/
|
|
2003
|
+
body?: TBody;
|
|
2004
|
+
/**
|
|
2005
|
+
* 响应 Schema
|
|
2006
|
+
*/
|
|
2007
|
+
response: TResponse;
|
|
2008
|
+
/**
|
|
2009
|
+
* 接口摘要描述
|
|
2010
|
+
*/
|
|
2011
|
+
summary?: string;
|
|
2012
|
+
/**
|
|
2013
|
+
* 接口标签,会与分组标签合并
|
|
2014
|
+
*/
|
|
2015
|
+
tags?: string[];
|
|
2016
|
+
/**
|
|
2017
|
+
* 是否需要 CSRF 令牌保护
|
|
2018
|
+
*/
|
|
2019
|
+
csrf?: boolean;
|
|
2020
|
+
/**
|
|
2021
|
+
* 请求内容类型
|
|
2022
|
+
*/
|
|
2023
|
+
contentType?: 'json' | 'formData';
|
|
2024
|
+
/**
|
|
2025
|
+
* 覆盖分组的认证策略
|
|
2026
|
+
*
|
|
2027
|
+
* 用于覆盖父路由分组的认证设置
|
|
2028
|
+
*/
|
|
2029
|
+
auth?: string;
|
|
2030
|
+
};
|
|
2031
|
+
/**
|
|
2032
|
+
* 路由定义结果类型
|
|
2033
|
+
*
|
|
2034
|
+
* defineRoute 返回的类型,包含完整的路由定义和可选的 auth 属性
|
|
2035
|
+
*
|
|
2036
|
+
* @typeParam TMethod - HTTP 方法类型
|
|
2037
|
+
* @typeParam TVersion - API 版本号类型
|
|
2038
|
+
* @typeParam TPrefix - 路径前缀类型
|
|
2039
|
+
* @typeParam TPath - 路径模板字符串
|
|
2040
|
+
* @typeParam TParams - 路径参数 Schema 类型
|
|
2041
|
+
* @typeParam TQuery - 查询参数 Schema 类型
|
|
2042
|
+
* @typeParam TBody - 请求体 Schema 类型
|
|
2043
|
+
* @typeParam TResponse - 响应 Schema 类型
|
|
2044
|
+
*/
|
|
2045
|
+
type RouteDefineResult<TMethod extends HttpMethod, TVersion extends ApiVersion | undefined, TPrefix extends string, TPath extends string, TParams extends ZodType | undefined, TQuery extends ZodType | undefined, TBody extends ZodType | undefined, TResponse extends ZodType> = RouteDefinition<TMethod, `${VersionedPrefix<TVersion, TPrefix>}${TPath}`, TParams, TQuery, TBody, TResponse> & {
|
|
2046
|
+
/**
|
|
2047
|
+
* 认证策略
|
|
2048
|
+
*/
|
|
2049
|
+
auth?: string;
|
|
2050
|
+
};
|
|
2051
|
+
/**
|
|
2052
|
+
* 已处理的路由类型
|
|
2053
|
+
*
|
|
2054
|
+
* defineRoute 方法返回的路由类型,或 defineRouteGroup 内部处理后的路由类型
|
|
2055
|
+
*
|
|
2056
|
+
* @typeParam T - 路由定义类型,保留 method 字面量和 Schema 类型信息
|
|
2057
|
+
*/
|
|
2058
|
+
type ProcessedRoute<T extends RouteDefinition = RouteDefinition> = T & {
|
|
2059
|
+
/**
|
|
2060
|
+
* 认证策略
|
|
2061
|
+
*/
|
|
2062
|
+
auth?: string;
|
|
2063
|
+
/**
|
|
2064
|
+
* 基础路径(NestJS 方法装饰器使用的相对路径)
|
|
2065
|
+
*/
|
|
2066
|
+
basePath?: string;
|
|
2067
|
+
/**
|
|
2068
|
+
* 接口摘要描述
|
|
2069
|
+
*/
|
|
2070
|
+
summary?: string;
|
|
2071
|
+
/**
|
|
2072
|
+
* 接口标签分组
|
|
2073
|
+
*/
|
|
2074
|
+
tags?: string[];
|
|
2075
|
+
/**
|
|
2076
|
+
* 是否需要 CSRF 令牌保护
|
|
2077
|
+
*/
|
|
2078
|
+
csrf?: boolean;
|
|
2079
|
+
/**
|
|
2080
|
+
* 请求内容类型
|
|
2081
|
+
*/
|
|
2082
|
+
contentType?: 'json' | 'formData';
|
|
2083
|
+
};
|
|
2084
|
+
/**
|
|
2085
|
+
* 从路由配置中提取 RouteDefinition 类型(保留具体类型信息)
|
|
2086
|
+
*
|
|
2087
|
+
* 通过直接检查输入类型的字段来推断类型,
|
|
2088
|
+
* 避免了 RouteDefineConfig 泛型默认值导致的类型丢失问题。
|
|
2089
|
+
* 使用 params?/query?/body? 推断来保留具体的 Zod Schema 类型,
|
|
2090
|
+
* 当字段不存在时推断为 undefined。
|
|
2091
|
+
*
|
|
2092
|
+
* @typeParam T - 路由配置值类型
|
|
2093
|
+
*/
|
|
2094
|
+
type InferRouteDefinitionFromValue<T> = T extends {
|
|
2095
|
+
/**
|
|
2096
|
+
* HTTP 方法
|
|
2097
|
+
*/
|
|
2098
|
+
method: infer M extends HttpMethod;
|
|
2099
|
+
/**
|
|
2100
|
+
* 请求路径
|
|
2101
|
+
*/
|
|
2102
|
+
path: string;
|
|
2103
|
+
/**
|
|
2104
|
+
* 响应 Schema
|
|
2105
|
+
*/
|
|
2106
|
+
response: infer R extends ZodType;
|
|
2107
|
+
/**
|
|
2108
|
+
* 路径参数 Schema
|
|
2109
|
+
*/
|
|
2110
|
+
params?: infer PA;
|
|
2111
|
+
/**
|
|
2112
|
+
* 查询参数 Schema
|
|
2113
|
+
*/
|
|
2114
|
+
query?: infer Q;
|
|
2115
|
+
/**
|
|
2116
|
+
* 请求体 Schema
|
|
2117
|
+
*/
|
|
2118
|
+
body?: infer B;
|
|
2119
|
+
} ? RouteDefinition<M, string, [PA] extends [ZodType] ? PA : undefined, [Q] extends [ZodType] ? Q : undefined, [B] extends [ZodType] ? B : undefined, R> & {
|
|
2120
|
+
/**
|
|
2121
|
+
* 接口摘要描述
|
|
2122
|
+
*/
|
|
2123
|
+
summary?: string;
|
|
2124
|
+
/**
|
|
2125
|
+
* 接口标签分组
|
|
2126
|
+
*/
|
|
2127
|
+
tags?: string[];
|
|
2128
|
+
/**
|
|
2129
|
+
* 是否需要 CSRF 令牌保护
|
|
2130
|
+
*/
|
|
2131
|
+
csrf?: boolean;
|
|
2132
|
+
/**
|
|
2133
|
+
* 请求内容类型
|
|
2134
|
+
*/
|
|
2135
|
+
contentType?: 'json' | 'formData';
|
|
2136
|
+
} : RouteDefinition;
|
|
2137
|
+
/**
|
|
2138
|
+
* 处理路由集合类型
|
|
2139
|
+
*
|
|
2140
|
+
* 从输入的路由定义集合中提取每个路由的具体类型信息,
|
|
2141
|
+
* 保留 method 字面量类型和 Schema 类型信息
|
|
2142
|
+
*
|
|
2143
|
+
* @typeParam TRoutes - 路由定义集合类型
|
|
2144
|
+
*/
|
|
2145
|
+
type ProcessRoutes<TRoutes extends Record<string, RouteDefineConfig | ProcessedRoute<RouteDefinition>>> = { [K in keyof TRoutes]: ProcessedRoute<InferRouteDefinitionFromValue<TRoutes[K]>> };
|
|
2146
|
+
/**
|
|
2147
|
+
* 定义路由分组(含 routes,保留具体键类型)
|
|
2148
|
+
*
|
|
2149
|
+
* 创建路由分组并附加路由定义,返回结果可直接用于 TypedController 和 TypedRoute。
|
|
2150
|
+
* routes 字段同时接受内联原始配置和 group.defineRoute() 的返回值。
|
|
2151
|
+
*
|
|
2152
|
+
* 重载顺序说明:此重载必须排在无 routes 重载之前。
|
|
2153
|
+
* 因为 RouteGroupConfig 中 routes 是可选字段,若宽泛重载在前,
|
|
2154
|
+
* TypeScript 会优先匹配宽泛签名,导致带 routes 的调用丢失 routes 类型信息。
|
|
2155
|
+
*
|
|
2156
|
+
* @typeParam TPrefix - 路径前缀类型
|
|
2157
|
+
* @typeParam TVersion - API 版本号类型
|
|
2158
|
+
* @typeParam TAuthStrategy - 认证策略类型
|
|
2159
|
+
* @typeParam TRoutes - 路由定义集合类型,保留具体键名用于类型推断
|
|
2160
|
+
* @param config - 分组配置(含 routes)
|
|
2161
|
+
* @returns 路由分组对象(含 routes 属性)
|
|
2162
|
+
*/
|
|
2163
|
+
declare function defineRouteGroup<TPrefix extends string = '', TVersion extends ApiVersion | undefined = undefined, TAuthStrategy extends string = DefaultAuthStrategy, TRoutes extends Record<string, RouteDefineConfig | ProcessedRoute<RouteDefinition>> = Record<string, RouteDefineConfig | ProcessedRoute<RouteDefinition>>>(config: RouteGroupConfig<TPrefix, TVersion, TAuthStrategy> & {
|
|
2164
|
+
/**
|
|
2165
|
+
* 路由定义集合
|
|
2166
|
+
*/
|
|
2167
|
+
routes: TRoutes;
|
|
2168
|
+
}): RouteGroup<TPrefix, TVersion, TAuthStrategy> & {
|
|
2169
|
+
/**
|
|
2170
|
+
* 路由定义集合(只读,保留具体键类型和 method 字面量类型)
|
|
2171
|
+
*/
|
|
2172
|
+
readonly routes: Readonly<ProcessRoutes<TRoutes>>;
|
|
2173
|
+
};
|
|
2174
|
+
/**
|
|
2175
|
+
* 定义路由分组(无 routes,用于 defineRoute 拆分定义的中间分组)
|
|
2176
|
+
*
|
|
2177
|
+
* @typeParam TPrefix - 路径前缀类型
|
|
2178
|
+
* @typeParam TVersion - API 版本号类型
|
|
2179
|
+
* @typeParam TAuthStrategy - 认证策略类型
|
|
2180
|
+
* @param config - 分组配置(不含 routes)
|
|
2181
|
+
* @returns 路由分组对象(提供 defineRoute 语法糖)
|
|
2182
|
+
*/
|
|
2183
|
+
declare function defineRouteGroup<TPrefix extends string = '', TVersion extends ApiVersion | undefined = undefined, TAuthStrategy extends string = DefaultAuthStrategy>(config: RouteGroupConfig<TPrefix, TVersion, TAuthStrategy>): RouteGroup<TPrefix, TVersion, TAuthStrategy>;
|
|
2184
|
+
//#endregion
|
|
2185
|
+
//#region src/factory/create-api-functions.factory.d.ts
|
|
2186
|
+
/**
|
|
2187
|
+
* 创建 GET 请求函数类型
|
|
2188
|
+
*
|
|
2189
|
+
* @typeParam TRoute - 路由定义类型
|
|
2190
|
+
*/
|
|
2191
|
+
type CreateGetFunction<TRoute extends RouteDefinition> = InferRouteParams<TRoute> extends undefined ? InferRouteQuery<TRoute> extends undefined ? () => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteQuery<TRoute> extends undefined ? (params: InferRouteParams<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (params: InferRouteParams<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>>;
|
|
2192
|
+
/**
|
|
2193
|
+
* 创建 POST 请求函数类型
|
|
2194
|
+
*
|
|
2195
|
+
* @typeParam TRoute - 路由定义类型
|
|
2196
|
+
*/
|
|
2197
|
+
type CreatePostFunction<TRoute extends RouteDefinition> = InferRouteParams<TRoute> extends undefined ? InferRouteBody<TRoute> extends undefined ? InferRouteQuery<TRoute> extends undefined ? () => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteQuery<TRoute> extends undefined ? (body: InferRouteBody<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (body: InferRouteBody<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteBody<TRoute> extends undefined ? InferRouteQuery<TRoute> extends undefined ? (params: InferRouteParams<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (params: InferRouteParams<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteQuery<TRoute> extends undefined ? (params: InferRouteParams<TRoute>, body: InferRouteBody<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (params: InferRouteParams<TRoute>, body: InferRouteBody<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>>;
|
|
2198
|
+
/**
|
|
2199
|
+
* 创建 PUT/PATCH 请求函数类型
|
|
2200
|
+
*
|
|
2201
|
+
* @typeParam TRoute - 路由定义类型
|
|
2202
|
+
*/
|
|
2203
|
+
type CreateUpdateFunction<TRoute extends RouteDefinition> = InferRouteParams<TRoute> extends undefined ? InferRouteBody<TRoute> extends undefined ? InferRouteQuery<TRoute> extends undefined ? () => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteQuery<TRoute> extends undefined ? (body: InferRouteBody<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (body: InferRouteBody<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteBody<TRoute> extends undefined ? InferRouteQuery<TRoute> extends undefined ? (params: InferRouteParams<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (params: InferRouteParams<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteQuery<TRoute> extends undefined ? (params: InferRouteParams<TRoute>, body: InferRouteBody<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (params: InferRouteParams<TRoute>, body: InferRouteBody<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>>;
|
|
2204
|
+
/**
|
|
2205
|
+
* 创建 DELETE 请求函数类型
|
|
2206
|
+
*
|
|
2207
|
+
* @typeParam TRoute - 路由定义类型
|
|
2208
|
+
*/
|
|
2209
|
+
type CreateDeleteFunction<TRoute extends RouteDefinition> = InferRouteParams<TRoute> extends undefined ? InferRouteQuery<TRoute> extends undefined ? () => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : InferRouteQuery<TRoute> extends undefined ? (params: InferRouteParams<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>> : (params: InferRouteParams<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<ApiResponse<InferRouteResponse<TRoute>>>;
|
|
2210
|
+
/**
|
|
2211
|
+
* HTTP 方法类型
|
|
2212
|
+
*/
|
|
2213
|
+
type MethodType = {
|
|
2214
|
+
/**
|
|
2215
|
+
* HTTP 方法
|
|
2216
|
+
*/
|
|
2217
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
2218
|
+
};
|
|
2219
|
+
/**
|
|
2220
|
+
* 根据路由定义创建对应的 API 函数类型
|
|
2221
|
+
*
|
|
2222
|
+
* @typeParam TRoute - 路由定义类型
|
|
2223
|
+
*/
|
|
2224
|
+
type CreateApiFunction<TRoute extends RouteDefinition> = TRoute extends MethodType ? CreateMethodFunction<TRoute> : () => Promise<ApiResponse<InferRouteResponse<TRoute>>>;
|
|
2225
|
+
/**
|
|
2226
|
+
* 根据 HTTP 方法创建对应的函数类型
|
|
2227
|
+
*
|
|
2228
|
+
* @typeParam TRoute - 路由定义类型
|
|
2229
|
+
*/
|
|
2230
|
+
type CreateMethodFunction<TRoute extends RouteDefinition> = TRoute extends {
|
|
2231
|
+
/**
|
|
2232
|
+
* HTTP 方法
|
|
2233
|
+
*/
|
|
2234
|
+
method: 'GET';
|
|
2235
|
+
} ? CreateGetFunction<TRoute> : TRoute extends {
|
|
2236
|
+
/**
|
|
2237
|
+
* HTTP 方法
|
|
2238
|
+
*/
|
|
2239
|
+
method: 'POST';
|
|
2240
|
+
} ? CreatePostFunction<TRoute> : TRoute extends {
|
|
2241
|
+
/**
|
|
2242
|
+
* HTTP 方法
|
|
2243
|
+
*/
|
|
2244
|
+
method: 'PUT';
|
|
2245
|
+
} ? CreateUpdateFunction<TRoute> : TRoute extends {
|
|
2246
|
+
/**
|
|
2247
|
+
* HTTP 方法
|
|
2248
|
+
*/
|
|
2249
|
+
method: 'PATCH';
|
|
2250
|
+
} ? CreateUpdateFunction<TRoute> : TRoute extends {
|
|
2251
|
+
/**
|
|
2252
|
+
* HTTP 方法
|
|
2253
|
+
*/
|
|
2254
|
+
method: 'DELETE';
|
|
2255
|
+
} ? CreateDeleteFunction<TRoute> : never;
|
|
2256
|
+
/**
|
|
2257
|
+
* 从路由定义对象创建 API 函数对象类型
|
|
2258
|
+
*
|
|
2259
|
+
* @typeParam TRoutes - 路由定义集合类型
|
|
2260
|
+
*/
|
|
2261
|
+
type ApiFunctions<TRoutes extends Record<string, RouteDefinition>> = { [K in keyof TRoutes]: CreateApiFunction<TRoutes[K]> };
|
|
2262
|
+
/**
|
|
2263
|
+
* API 客户端工厂函数类型
|
|
2264
|
+
*
|
|
2265
|
+
* 接收路由定义集合,返回对应的 API 函数对象
|
|
2266
|
+
*
|
|
2267
|
+
* @typeParam TRoutes - 路由定义集合类型
|
|
2268
|
+
*/
|
|
2269
|
+
type CreateApiFromRoutes = <TRoutes extends Record<string, RouteDefinition>>(routes: TRoutes) => ApiFunctions<TRoutes>;
|
|
2270
|
+
/**
|
|
2271
|
+
* API 客户端工厂
|
|
2272
|
+
*
|
|
2273
|
+
* 先绑定 HTTP 客户端,返回只需要路由定义的 createApi 函数。
|
|
2274
|
+
* 避免每次调用都传递 client 参数,符合"一次配置,到处使用"的理念。
|
|
2275
|
+
*
|
|
2276
|
+
* @example
|
|
2277
|
+
* ```typescript
|
|
2278
|
+
* // 一次绑定 client
|
|
2279
|
+
* const createApi = createApiClientFactory(httpClient);
|
|
2280
|
+
*
|
|
2281
|
+
* // 后续只需传 routes
|
|
2282
|
+
* const activityApi = createApi(activityRoutes.routes);
|
|
2283
|
+
* const categoryApi = createApi(categoryRoutes.routes);
|
|
2284
|
+
*
|
|
2285
|
+
* // 使用 -- 全链路强类型
|
|
2286
|
+
* const response = await activityApi.list({ page: 1 });
|
|
2287
|
+
* ```;
|
|
2288
|
+
*
|
|
2289
|
+
* @param client - HTTP 客户端实例
|
|
2290
|
+
* @returns 只需要 routes 参数的 createApi 函数
|
|
2291
|
+
*/
|
|
2292
|
+
declare function createApiClientFactory(client: HttpClient): CreateApiFromRoutes;
|
|
2293
|
+
//#endregion
|
|
2294
|
+
//#region src/utils/api-response.util.d.ts
|
|
2295
|
+
/**
|
|
2296
|
+
* API 响应工具类
|
|
2297
|
+
*
|
|
2298
|
+
* 提供统一的响应构建方法,确保所有响应结构一致
|
|
2299
|
+
*/
|
|
2300
|
+
declare const ApiResponseUtil: {
|
|
2301
|
+
/**
|
|
2302
|
+
* 构建成功响应
|
|
2303
|
+
*
|
|
2304
|
+
* @typeParam T - 响应数据类型
|
|
2305
|
+
* @param data - 响应数据
|
|
2306
|
+
* @param message - 响应消息
|
|
2307
|
+
* @returns 成功响应对象
|
|
2308
|
+
*/
|
|
2309
|
+
success<T>(data: T, message?: string): ApiSuccessResponse<T>;
|
|
2310
|
+
/**
|
|
2311
|
+
* 构建仅包含数据的成功响应
|
|
2312
|
+
*
|
|
2313
|
+
* @typeParam T - 响应数据类型
|
|
2314
|
+
* @param data - 响应数据
|
|
2315
|
+
* @returns 成功响应对象
|
|
2316
|
+
*/
|
|
2317
|
+
data<T>(data: T): ApiSuccessResponse<T>;
|
|
2318
|
+
/**
|
|
2319
|
+
* 构建仅包含消息的成功响应
|
|
2320
|
+
*
|
|
2321
|
+
* @param message - 响应消息
|
|
2322
|
+
* @returns 成功响应对象
|
|
2323
|
+
*/
|
|
2324
|
+
message(message: string): ApiSuccessResponse<undefined>;
|
|
2325
|
+
/**
|
|
2326
|
+
* 构建失败响应
|
|
2327
|
+
*
|
|
2328
|
+
* @typeParam T - 响应数据类型
|
|
2329
|
+
* @param message - 错误消息
|
|
2330
|
+
* @param data - 可选的响应数据
|
|
2331
|
+
* @returns 失败响应对象
|
|
2332
|
+
*/
|
|
2333
|
+
fail<T>(message: string, data?: T): ApiFailResponse<T>;
|
|
2334
|
+
/**
|
|
2335
|
+
* 构建空成功响应
|
|
2336
|
+
*
|
|
2337
|
+
* @typeParam T - 响应数据类型
|
|
2338
|
+
* @returns 空成功响应对象
|
|
2339
|
+
*/
|
|
2340
|
+
empty<T>(): ApiSuccessResponse<T | undefined>;
|
|
2341
|
+
};
|
|
2342
|
+
/**
|
|
2343
|
+
* API 列表数据工具类
|
|
2344
|
+
*
|
|
2345
|
+
* 用于构建 ApiResponse.data 字段的列表数据
|
|
2346
|
+
*/
|
|
2347
|
+
declare const ApiListDataUtil: {
|
|
2348
|
+
/**
|
|
2349
|
+
* 构建空列表数据
|
|
2350
|
+
*
|
|
2351
|
+
* @typeParam T - 列表项数据类型
|
|
2352
|
+
* @returns 空列表数据对象
|
|
2353
|
+
*/
|
|
2354
|
+
empty<T>(): ApiListData<T>;
|
|
2355
|
+
/**
|
|
2356
|
+
* 从数组构建列表数据(自动计算总数)
|
|
2357
|
+
*
|
|
2358
|
+
* @typeParam T - 列表项数据类型
|
|
2359
|
+
* @param items - 数据项数组
|
|
2360
|
+
* @returns 列表数据对象
|
|
2361
|
+
*/
|
|
2362
|
+
from<T>(items: T[]): ApiListData<T>;
|
|
2363
|
+
/**
|
|
2364
|
+
* 从数组和总数构建列表数据
|
|
2365
|
+
*
|
|
2366
|
+
* @typeParam T - 列表项数据类型
|
|
2367
|
+
* @param items - 数据项数组
|
|
2368
|
+
* @param total - 总记录数
|
|
2369
|
+
* @returns 列表数据对象
|
|
2370
|
+
*/
|
|
2371
|
+
withTotal<T>(items: T[], total: number): ApiListData<T>;
|
|
2372
|
+
/**
|
|
2373
|
+
* 构建完整分页列表数据
|
|
2374
|
+
*
|
|
2375
|
+
* 委托给 @longzai-intelligence/pagination 的 createPaginatedResult
|
|
2376
|
+
*
|
|
2377
|
+
* @typeParam T - 列表项数据类型
|
|
2378
|
+
* @param items - 数据项数组
|
|
2379
|
+
* @param total - 总记录数
|
|
2380
|
+
* @param page - 当前页码
|
|
2381
|
+
* @param pageSize - 每页数量
|
|
2382
|
+
* @returns 分页列表数据对象
|
|
2383
|
+
*/
|
|
2384
|
+
paginated<T>(items: T[], total: number, page: number, pageSize: number): ApiPaginatedListData<T>;
|
|
2385
|
+
};
|
|
2386
|
+
//#endregion
|
|
2387
|
+
//#region src/utils/form-data.util.d.ts
|
|
2388
|
+
/**
|
|
2389
|
+
* FormData 转换配置
|
|
2390
|
+
*/
|
|
2391
|
+
type FormDataConvertConfig = {
|
|
2392
|
+
/**
|
|
2393
|
+
* 文件字段名列表
|
|
2394
|
+
*
|
|
2395
|
+
* 指定哪些字段应该作为文件处理
|
|
2396
|
+
*/
|
|
2397
|
+
fileFields?: string[];
|
|
2398
|
+
/**
|
|
2399
|
+
* 数组处理方式
|
|
2400
|
+
*
|
|
2401
|
+
* - 'indices':使用索引(field[0], field[1])
|
|
2402
|
+
* - 'brackets':使用括号(field[], field[])
|
|
2403
|
+
* - 'repeat':重复字段名(field, field)
|
|
2404
|
+
*/
|
|
2405
|
+
arrayFormat?: 'indices' | 'brackets' | 'repeat';
|
|
2406
|
+
};
|
|
2407
|
+
/**
|
|
2408
|
+
* 判断是否为文件对象
|
|
2409
|
+
*
|
|
2410
|
+
* @param value - 待判断的值
|
|
2411
|
+
* @returns 是否为文件对象
|
|
2412
|
+
*/
|
|
2413
|
+
declare function isFile(value: unknown): value is File;
|
|
2414
|
+
/**
|
|
2415
|
+
* 判断是否为 Blob 对象
|
|
2416
|
+
*
|
|
2417
|
+
* @param value - 待判断的值
|
|
2418
|
+
* @returns 是否为 Blob 对象
|
|
2419
|
+
*/
|
|
2420
|
+
declare function isBlob(value: unknown): value is Blob;
|
|
2421
|
+
/**
|
|
2422
|
+
* 将对象转换为 FormData
|
|
2423
|
+
*
|
|
2424
|
+
* @example
|
|
2425
|
+
* ```typescript
|
|
2426
|
+
* import { objectToFormData } from '@longzai-intelligence-transport/http';
|
|
2427
|
+
*
|
|
2428
|
+
* const formData = objectToFormData(
|
|
2429
|
+
* {
|
|
2430
|
+
* name: 'Test',
|
|
2431
|
+
* file: new File(['content'], 'test.txt'),
|
|
2432
|
+
* },
|
|
2433
|
+
* {
|
|
2434
|
+
* fileFields: ['file'],
|
|
2435
|
+
* },
|
|
2436
|
+
* );
|
|
2437
|
+
* ```;
|
|
2438
|
+
*
|
|
2439
|
+
* @param obj - 要转换的对象
|
|
2440
|
+
* @param config - 转换配置
|
|
2441
|
+
* @returns FormData 实例
|
|
2442
|
+
*/
|
|
2443
|
+
declare function objectToFormData(obj: Record<string, unknown>, config?: FormDataConvertConfig): FormData;
|
|
2444
|
+
/**
|
|
2445
|
+
* 判断路由是否需要 FormData
|
|
2446
|
+
*
|
|
2447
|
+
* @param contentType - 内容类型
|
|
2448
|
+
* @returns 是否需要 FormData
|
|
2449
|
+
*/
|
|
2450
|
+
declare function isFormDataContentType(contentType?: 'json' | 'formData'): boolean;
|
|
2451
|
+
//#endregion
|
|
2452
|
+
//#region src/utils/route-response-builder.util.d.ts
|
|
2453
|
+
/**
|
|
2454
|
+
* 路由响应构建器
|
|
2455
|
+
*
|
|
2456
|
+
* 提供类型安全的响应构建方法,响应数据类型从 RouteDefinition 自动推断
|
|
2457
|
+
*
|
|
2458
|
+
* @typeParam TRoute - 路由定义类型
|
|
2459
|
+
*/
|
|
2460
|
+
type RouteResponseBuilder<TRoute extends RouteDefinition> = {
|
|
2461
|
+
/**
|
|
2462
|
+
* 构建成功响应
|
|
2463
|
+
*
|
|
2464
|
+
* @param data - 响应数据,类型从 RouteDefinition 自动推断
|
|
2465
|
+
* @returns 成功响应对象
|
|
2466
|
+
*/
|
|
2467
|
+
success: (data: InferRouteResponse<TRoute>) => ApiResponse<InferRouteResponse<TRoute>>;
|
|
2468
|
+
/**
|
|
2469
|
+
* 构建带消息的成功响应
|
|
2470
|
+
*
|
|
2471
|
+
* @param data - 响应数据
|
|
2472
|
+
* @param message - 响应消息
|
|
2473
|
+
* @returns 成功响应对象
|
|
2474
|
+
*/
|
|
2475
|
+
successWithMessage: (data: InferRouteResponse<TRoute>, message: string) => ApiResponse<InferRouteResponse<TRoute>>;
|
|
2476
|
+
/**
|
|
2477
|
+
* 构建失败响应
|
|
2478
|
+
*
|
|
2479
|
+
* @param message - 错误消息
|
|
2480
|
+
* @param error - 可选的错误详情
|
|
2481
|
+
* @returns 失败响应对象
|
|
2482
|
+
*/
|
|
2483
|
+
fail: (message: string, error?: ApiError) => ApiResponse<never>;
|
|
2484
|
+
/**
|
|
2485
|
+
* 构建空响应
|
|
2486
|
+
*
|
|
2487
|
+
* @returns 空成功响应对象
|
|
2488
|
+
*/
|
|
2489
|
+
empty: () => ApiResponse<InferRouteResponse<TRoute>>;
|
|
2490
|
+
};
|
|
2491
|
+
/**
|
|
2492
|
+
* 从路由定义创建类型安全的服务端响应构建器
|
|
2493
|
+
*
|
|
2494
|
+
* 响应数据类型从 RouteDefinition 自动推断,确保服务端返回的数据类型与路由定义一致
|
|
2495
|
+
*
|
|
2496
|
+
* @example
|
|
2497
|
+
* ```typescript
|
|
2498
|
+
* import { createRouteResponseBuilder, defineRoute, z } from '@longzai-intelligence-transport/http';
|
|
2499
|
+
*
|
|
2500
|
+
* const userRoute = defineRoute({
|
|
2501
|
+
* method: 'GET',
|
|
2502
|
+
* path: '/users/:id',
|
|
2503
|
+
* params: z.object({ id: z.string() }),
|
|
2504
|
+
* response: z.object({ id: z.string(), name: z.string() }),
|
|
2505
|
+
* });
|
|
2506
|
+
*
|
|
2507
|
+
* const builder = createRouteResponseBuilder(userRoute);
|
|
2508
|
+
*
|
|
2509
|
+
* // 类型安全:data 必须符合 { id: string, name: string }
|
|
2510
|
+
* const response = builder.success({ id: '123', name: 'John' });
|
|
2511
|
+
*
|
|
2512
|
+
* // 编译错误:缺少 name 字段
|
|
2513
|
+
* // builder.success({ id: '123' });
|
|
2514
|
+
* ```;
|
|
2515
|
+
*
|
|
2516
|
+
* @typeParam TRoute - 路由定义类型
|
|
2517
|
+
* @param route - 路由定义
|
|
2518
|
+
* @returns 类型安全的响应构建器
|
|
2519
|
+
*/
|
|
2520
|
+
declare function createRouteResponseBuilder<TRoute extends RouteDefinition>(route: TRoute): RouteResponseBuilder<TRoute>;
|
|
2521
|
+
/**
|
|
2522
|
+
* 类型安全的成功响应函数类型
|
|
2523
|
+
*
|
|
2524
|
+
* @typeParam R - 路由定义类型
|
|
2525
|
+
*/
|
|
2526
|
+
type TypedResponseFunction<R extends RouteDefinition> = (data: InferRouteResponse<R>) => ApiResponse<InferRouteResponse<R>>;
|
|
2527
|
+
/**
|
|
2528
|
+
* 类型安全的空响应函数类型
|
|
2529
|
+
*/
|
|
2530
|
+
type TypedEmptyFunction = () => ApiResponse<void>;
|
|
2531
|
+
/**
|
|
2532
|
+
* 创建类型安全的成功响应函数
|
|
2533
|
+
*
|
|
2534
|
+
* 工厂模式: 创建时绑定路由定义,返回的函数只接受 data 参数。
|
|
2535
|
+
* data 的类型由路由 response Schema 推导,编译期检查数据结构一致性。
|
|
2536
|
+
*
|
|
2537
|
+
* @example
|
|
2538
|
+
* ```typescript
|
|
2539
|
+
* const typedResponse = createTypedResponse(userListRoute);
|
|
2540
|
+
* return typedResponse({ items: [...], pagination: {...} });
|
|
2541
|
+
* ```;
|
|
2542
|
+
*
|
|
2543
|
+
* @typeParam R - 路由定义类型
|
|
2544
|
+
* @param _route - 路由定义(创建时绑定,用于类型推断)
|
|
2545
|
+
* @returns 响应函数,接受 data 参数,返回 ApiResponse
|
|
2546
|
+
*/
|
|
2547
|
+
declare function createTypedResponse<R extends RouteDefinition>(_route: R): TypedResponseFunction<R>;
|
|
2548
|
+
/**
|
|
2549
|
+
* 创建类型安全的空响应函数
|
|
2550
|
+
*
|
|
2551
|
+
* 工厂模式: 创建时绑定路由定义,返回无参函数。
|
|
2552
|
+
*
|
|
2553
|
+
* @example
|
|
2554
|
+
* ```typescript
|
|
2555
|
+
* const typedEmpty = createTypedEmpty(userDeleteRoute);
|
|
2556
|
+
* return typedEmpty();
|
|
2557
|
+
* ```;
|
|
2558
|
+
*
|
|
2559
|
+
* @typeParam R - 路由定义类型
|
|
2560
|
+
* @param _route - 路由定义(创建时绑定,用于类型推断)
|
|
2561
|
+
* @returns 无参函数,返回空 ApiResponse
|
|
2562
|
+
*/
|
|
2563
|
+
declare function createTypedEmpty<R extends RouteDefinition>(_route: R): TypedEmptyFunction;
|
|
2564
|
+
//#endregion
|
|
2565
|
+
//#region src/utils/unwrap-result.util.d.ts
|
|
2566
|
+
/**
|
|
2567
|
+
* 将 Result 显式转换为 ApiResponse
|
|
2568
|
+
*
|
|
2569
|
+
* 用于控制器层,将领域层的 Result 类型解包为传输层的 ApiResponse。
|
|
2570
|
+
* Success 时提取 value 包装为标准响应,Failure 时抛出错误由异常过滤器处理。
|
|
2571
|
+
*
|
|
2572
|
+
* @typeParam T - Result 中成功值的类型
|
|
2573
|
+
* @typeParam E - Result 中错误类型
|
|
2574
|
+
* @param result - 服务层返回的 Result 实例
|
|
2575
|
+
* @returns 标准化的 API 响应
|
|
2576
|
+
* @throws {@link Error} Result 为 Failure 时抛出 error,由 HttpExceptionFilter 处理
|
|
2577
|
+
*/
|
|
2578
|
+
declare function unwrapResult<T, E>(result: Result<T, E>): ApiResponse<T>;
|
|
2579
|
+
//#endregion
|
|
2580
|
+
//#region src/utils/type-guards.util.d.ts
|
|
2581
|
+
/**
|
|
2582
|
+
* 类型守卫工具
|
|
2583
|
+
*
|
|
2584
|
+
* 提供通用的类型守卫函数,用于替代 as 类型断言。
|
|
2585
|
+
* 遵循项目规范:使用类型守卫或 Zod 进行类型收窄。
|
|
2586
|
+
*/
|
|
2587
|
+
/**
|
|
2588
|
+
* 检查值是否为普通对象(非数组、非 null)
|
|
2589
|
+
*
|
|
2590
|
+
* @param value - 待检查的值
|
|
2591
|
+
* @returns 是否为普通对象
|
|
2592
|
+
*/
|
|
2593
|
+
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
2594
|
+
/**
|
|
2595
|
+
* 检查值是否为指定类型(通用类型守卫)
|
|
2596
|
+
*
|
|
2597
|
+
* 用于工厂模式中无法通过 Zod 验证的泛型类型收窄。
|
|
2598
|
+
* 运行时仅检查值是否存在且不为 undefined,实际类型安全性由 TypeScript 泛型保证。
|
|
2599
|
+
*
|
|
2600
|
+
* @typeParam T - 目标类型
|
|
2601
|
+
* @param value - 待检查的值
|
|
2602
|
+
* @returns 是否为指定类型
|
|
2603
|
+
*/
|
|
2604
|
+
declare function isType<T>(value: unknown): value is T;
|
|
2605
|
+
//#endregion
|
|
2606
|
+
//#region src/client/create-http-client.utils.d.ts
|
|
2607
|
+
/**
|
|
2608
|
+
* 创建 HTTP 客户端
|
|
2609
|
+
*
|
|
2610
|
+
* 创建配置好的 HTTP 客户端实例,提供统一的 REST 风格请求/响应处理。
|
|
2611
|
+
* 返回的客户端提供类型安全的 request 方法。
|
|
2612
|
+
*
|
|
2613
|
+
* 支持拦截器模式进行扩展。
|
|
2614
|
+
*
|
|
2615
|
+
* @example
|
|
2616
|
+
* ```typescript
|
|
2617
|
+
* import {
|
|
2618
|
+
* createHttpClient,
|
|
2619
|
+
* createAuthTokenInterceptor,
|
|
2620
|
+
* createLoggingInterceptor,
|
|
2621
|
+
* } from '@longzai-intelligence-transport/http';
|
|
2622
|
+
*
|
|
2623
|
+
* const loggingInterceptor = createLoggingInterceptor({ level: 'debug' });
|
|
2624
|
+
*
|
|
2625
|
+
* const client = createHttpClient({
|
|
2626
|
+
* baseUrl: 'https://api.example.com',
|
|
2627
|
+
* requestInterceptors: [loggingInterceptor.request, createAuthTokenInterceptor(tokenProvider)],
|
|
2628
|
+
* responseInterceptors: [loggingInterceptor.response],
|
|
2629
|
+
* });
|
|
2630
|
+
*
|
|
2631
|
+
* // 使用类型安全的 request 方法
|
|
2632
|
+
* const response = await client.request({ route: userRoutes.list });
|
|
2633
|
+
* ```;
|
|
2634
|
+
*
|
|
2635
|
+
* @param config - 客户端配置
|
|
2636
|
+
* @returns HTTP 客户端实例
|
|
2637
|
+
*/
|
|
2638
|
+
declare function createHttpClient(config: HttpClientConfig): HttpClient;
|
|
2639
|
+
//#endregion
|
|
2640
|
+
//#region src/client/index.d.ts
|
|
2641
|
+
/**
|
|
2642
|
+
* 设置 HTTP 客户端配置
|
|
2643
|
+
*
|
|
2644
|
+
* 供 orval 生成的客户端使用,配置 axios 实例的基础 URL、超时和认证
|
|
2645
|
+
*
|
|
2646
|
+
* @param config - 客户端配置
|
|
2647
|
+
*/
|
|
2648
|
+
declare function setHttpClientConfig(config: HttpClientConfig): void;
|
|
2649
|
+
/**
|
|
2650
|
+
* 创建 orval 使用的 axios 实例
|
|
2651
|
+
*
|
|
2652
|
+
* 供 orval 生成的客户端调用,根据 setHttpClientConfig 配置创建 axios 实例
|
|
2653
|
+
*
|
|
2654
|
+
* @typeParam T - 响应数据类型
|
|
2655
|
+
* @param config - Axios 请求配置
|
|
2656
|
+
* @returns Axios 响应对象
|
|
2657
|
+
*/
|
|
2658
|
+
declare function createAxiosInstance<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
2659
|
+
//#endregion
|
|
2660
|
+
//#region src/adapters/adapter.types.d.ts
|
|
2661
|
+
/**
|
|
2662
|
+
* HTTP 适配器接口
|
|
2663
|
+
*
|
|
2664
|
+
* 各运行时环境需实现此接口,拦截器执行器调用适配器执行实际 HTTP 请求
|
|
2665
|
+
*/
|
|
2666
|
+
type HttpAdapter = {
|
|
2667
|
+
/**
|
|
2668
|
+
* 执行 HTTP 请求
|
|
2669
|
+
*
|
|
2670
|
+
* @param context - 请求上下文(已通过请求拦截器处理)
|
|
2671
|
+
* @returns 原始响应数据
|
|
2672
|
+
*/
|
|
2673
|
+
execute(context: RequestInterceptorContext): Promise<{
|
|
2674
|
+
/**
|
|
2675
|
+
* HTTP 状态码
|
|
2676
|
+
*/
|
|
2677
|
+
status: number;
|
|
2678
|
+
/**
|
|
2679
|
+
* 响应头
|
|
2680
|
+
*/
|
|
2681
|
+
headers: Record<string, string>;
|
|
2682
|
+
/**
|
|
2683
|
+
* 响应数据
|
|
2684
|
+
*/
|
|
2685
|
+
data: unknown;
|
|
2686
|
+
}>;
|
|
2687
|
+
/**
|
|
2688
|
+
* 取消请求
|
|
2689
|
+
*
|
|
2690
|
+
* @param requestId - 请求标识
|
|
2691
|
+
*/
|
|
2692
|
+
abort?(requestId: string): void;
|
|
2693
|
+
};
|
|
2694
|
+
/**
|
|
2695
|
+
* Axios 适配器配置
|
|
2696
|
+
*/
|
|
2697
|
+
type AxiosAdapterConfig = {
|
|
2698
|
+
/**
|
|
2699
|
+
* 请求超时时间(毫秒)
|
|
2700
|
+
*/
|
|
2701
|
+
timeout?: number;
|
|
2702
|
+
};
|
|
2703
|
+
/**
|
|
2704
|
+
* Taro 适配器配置
|
|
2705
|
+
*/
|
|
2706
|
+
type TaroAdapterConfig = {
|
|
2707
|
+
/**
|
|
2708
|
+
* 请求超时时间(毫秒)
|
|
2709
|
+
*/
|
|
2710
|
+
timeout?: number;
|
|
2711
|
+
};
|
|
2712
|
+
//#endregion
|
|
2713
|
+
//#region src/adapters/axios.adapter.d.ts
|
|
2714
|
+
/**
|
|
2715
|
+
* 创建 Axios 适配器
|
|
2716
|
+
*
|
|
2717
|
+
* @param config - 适配器配置
|
|
2718
|
+
* @returns HTTP 适配器实例
|
|
2719
|
+
*/
|
|
2720
|
+
declare function createAxiosAdapter(config?: AxiosAdapterConfig): HttpAdapter;
|
|
2721
|
+
//#endregion
|
|
2722
|
+
//#region src/mock/index.d.ts
|
|
2723
|
+
/**
|
|
2724
|
+
* Mock 请求类型
|
|
2725
|
+
*
|
|
2726
|
+
* 描述一个模拟请求的配置
|
|
2727
|
+
*/
|
|
2728
|
+
type MockRequest = {
|
|
2729
|
+
/**
|
|
2730
|
+
* HTTP 方法
|
|
2731
|
+
*/
|
|
2732
|
+
method?: string;
|
|
2733
|
+
/**
|
|
2734
|
+
* 路径模式(支持通配符)
|
|
2735
|
+
*/
|
|
2736
|
+
path?: string;
|
|
2737
|
+
/**
|
|
2738
|
+
* 匹配条件函数
|
|
2739
|
+
*/
|
|
2740
|
+
match?: (route: RouteDefinition, params?: unknown, query?: unknown, body?: unknown) => boolean;
|
|
2741
|
+
/**
|
|
2742
|
+
* 响应数据或响应生成函数
|
|
2743
|
+
*/
|
|
2744
|
+
response: ApiResponse<unknown> | ((context: MockRequestContext) => ApiResponse<unknown>);
|
|
2745
|
+
/**
|
|
2746
|
+
* 响应延迟(毫秒)
|
|
2747
|
+
*/
|
|
2748
|
+
delay?: number;
|
|
2749
|
+
};
|
|
2750
|
+
/**
|
|
2751
|
+
* Mock 请求上下文
|
|
2752
|
+
*
|
|
2753
|
+
* 描述模拟请求执行时的上下文信息
|
|
2754
|
+
*/
|
|
2755
|
+
type MockRequestContext = {
|
|
2756
|
+
/**
|
|
2757
|
+
* 路由定义
|
|
2758
|
+
*/
|
|
2759
|
+
route: RouteDefinition;
|
|
2760
|
+
/**
|
|
2761
|
+
* 路径参数
|
|
2762
|
+
*/
|
|
2763
|
+
params?: unknown;
|
|
2764
|
+
/**
|
|
2765
|
+
* 查询参数
|
|
2766
|
+
*/
|
|
2767
|
+
query?: unknown;
|
|
2768
|
+
/**
|
|
2769
|
+
* 请求体
|
|
2770
|
+
*/
|
|
2771
|
+
body?: unknown;
|
|
2772
|
+
};
|
|
2773
|
+
/**
|
|
2774
|
+
* 路由模拟请求选项类型
|
|
2775
|
+
*
|
|
2776
|
+
* @typeParam TRoute - 路由定义类型
|
|
2777
|
+
*/
|
|
2778
|
+
type RouteMockRequestOptions<TRoute extends RouteDefinition> = {
|
|
2779
|
+
/**
|
|
2780
|
+
* 路由定义
|
|
2781
|
+
*/
|
|
2782
|
+
route: TRoute;
|
|
2783
|
+
/**
|
|
2784
|
+
* 路径参数
|
|
2785
|
+
*/
|
|
2786
|
+
params?: unknown;
|
|
2787
|
+
/**
|
|
2788
|
+
* 查询参数
|
|
2789
|
+
*/
|
|
2790
|
+
query?: unknown;
|
|
2791
|
+
/**
|
|
2792
|
+
* 请求体
|
|
2793
|
+
*/
|
|
2794
|
+
body?: unknown;
|
|
2795
|
+
};
|
|
2796
|
+
/**
|
|
2797
|
+
* 创建模拟 HTTP 客户端
|
|
2798
|
+
*
|
|
2799
|
+
* @example
|
|
2800
|
+
* ```typescript
|
|
2801
|
+
* import { createMockHttpClient } from '@longzai-intelligence-transport/http';
|
|
2802
|
+
*
|
|
2803
|
+
* const mockClient = createMockHttpClient({
|
|
2804
|
+
* success: true,
|
|
2805
|
+
* data: { id: 1, name: 'Test' },
|
|
2806
|
+
* });
|
|
2807
|
+
* ```;
|
|
2808
|
+
*
|
|
2809
|
+
* @typeParam T - 响应数据类型
|
|
2810
|
+
* @param mockResponse - 模拟响应数据
|
|
2811
|
+
* @returns 模拟的 HttpClient 实例
|
|
2812
|
+
* @throws {@link Error} 当模拟响应类型不匹配时抛出错误
|
|
2813
|
+
*/
|
|
2814
|
+
declare function createMockHttpClient<T>(mockResponse: ApiResponse<T>): HttpClient;
|
|
2815
|
+
/**
|
|
2816
|
+
* 创建可配置的模拟 HTTP 客户端
|
|
2817
|
+
*
|
|
2818
|
+
* @example
|
|
2819
|
+
* ```typescript
|
|
2820
|
+
* import { createConfigurableMockHttpClient } from '@longzai-intelligence-transport/http';
|
|
2821
|
+
*
|
|
2822
|
+
* const responses = new Map([
|
|
2823
|
+
* ['GET:/users', { success: true, data: [{ id: 1, name: 'User 1' }] }],
|
|
2824
|
+
* ['POST:/users', { success: true, data: { id: 2, name: 'New User' } }],
|
|
2825
|
+
* ]);
|
|
2826
|
+
*
|
|
2827
|
+
* const mockClient = createConfigurableMockHttpClient(responses);
|
|
2828
|
+
* ```;
|
|
2829
|
+
*
|
|
2830
|
+
* @param responses - 响应映射表,按路径和方法匹配
|
|
2831
|
+
* @returns 模拟的 HttpClient 实例
|
|
2832
|
+
* @throws {@link Error} 当模拟响应类型不匹配或创建失败时抛出错误
|
|
2833
|
+
*/
|
|
2834
|
+
declare function createConfigurableMockHttpClient(responses: Map<string, ApiResponse<unknown>>): HttpClient;
|
|
2835
|
+
/**
|
|
2836
|
+
* 创建延迟响应的模拟 HTTP 客户端
|
|
2837
|
+
*
|
|
2838
|
+
* @example
|
|
2839
|
+
* ```typescript
|
|
2840
|
+
* import { createDelayedMockHttpClient } from '@longzai-intelligence-transport/http';
|
|
2841
|
+
*
|
|
2842
|
+
* // 模拟 500ms 延迟
|
|
2843
|
+
* const mockClient = createDelayedMockHttpClient({ success: true, data: { id: 1 } }, 500);
|
|
2844
|
+
* ```;
|
|
2845
|
+
*
|
|
2846
|
+
* @typeParam T - 响应数据类型
|
|
2847
|
+
* @param mockResponse - 模拟响应数据
|
|
2848
|
+
* @param delay - 延迟时间(毫秒)
|
|
2849
|
+
* @returns 模拟的 HttpClient 实例
|
|
2850
|
+
* @throws {@link Error} 当模拟响应类型不匹配时抛出错误
|
|
2851
|
+
*/
|
|
2852
|
+
declare function createDelayedMockHttpClient<T>(mockResponse: ApiResponse<T>, delay: number): HttpClient;
|
|
2853
|
+
/**
|
|
2854
|
+
* 创建错误响应的模拟 HTTP 客户端
|
|
2855
|
+
*
|
|
2856
|
+
* @example
|
|
2857
|
+
* ```typescript
|
|
2858
|
+
* import { createErrorMockHttpClient } from '@longzai-intelligence-transport/http';
|
|
2859
|
+
*
|
|
2860
|
+
* const mockClient = createErrorMockHttpClient(new Error('Network error'));
|
|
2861
|
+
* ```;
|
|
2862
|
+
*
|
|
2863
|
+
* @param error - 要抛出的错误
|
|
2864
|
+
* @returns 模拟的 HttpClient 实例
|
|
2865
|
+
* @throws {@link Error} 总是抛出传入的错误
|
|
2866
|
+
*/
|
|
2867
|
+
declare function createErrorMockHttpClient(error: Error): HttpClient;
|
|
2868
|
+
/**
|
|
2869
|
+
* 创建基于路由定义的 Mock 客户端
|
|
2870
|
+
*
|
|
2871
|
+
* @example
|
|
2872
|
+
* ```typescript
|
|
2873
|
+
* import { createRouteMock, defineRoute, z } from '@longzai-intelligence-transport/http';
|
|
2874
|
+
*
|
|
2875
|
+
* const mockClient = createRouteMock([
|
|
2876
|
+
* {
|
|
2877
|
+
* path: '/users',
|
|
2878
|
+
* method: 'GET',
|
|
2879
|
+
* response: { success: true, data: [{ id: 1, name: 'User' }] },
|
|
2880
|
+
* },
|
|
2881
|
+
* {
|
|
2882
|
+
* match: (route) => route.method === 'POST' && route.path === '/users',
|
|
2883
|
+
* response: { success: true, data: { id: 2 } },
|
|
2884
|
+
* delay: 100,
|
|
2885
|
+
* },
|
|
2886
|
+
* ]);
|
|
2887
|
+
* ```;
|
|
2888
|
+
*
|
|
2889
|
+
* @param mocks - Mock 配置数组
|
|
2890
|
+
* @returns 模拟的 HttpClient 实例
|
|
2891
|
+
* @throws {@link Error} 当模拟响应类型不匹配或创建失败时抛出错误
|
|
2892
|
+
*/
|
|
2893
|
+
declare function createRouteMock(mocks: MockRequest[]): HttpClient;
|
|
2894
|
+
//#endregion
|
|
2895
|
+
//#region src/validation/index.d.ts
|
|
2896
|
+
/**
|
|
2897
|
+
* 验证错误详情项
|
|
2898
|
+
*
|
|
2899
|
+
* 描述单个字段的验证错误
|
|
2900
|
+
*/
|
|
2901
|
+
type ValidationErrorDetail = {
|
|
2902
|
+
/**
|
|
2903
|
+
* 字段路径
|
|
2904
|
+
*/
|
|
2905
|
+
path: string;
|
|
2906
|
+
/**
|
|
2907
|
+
* 错误消息
|
|
2908
|
+
*/
|
|
2909
|
+
message: string;
|
|
2910
|
+
/**
|
|
2911
|
+
* 实际接收到的值
|
|
2912
|
+
*/
|
|
2913
|
+
received: unknown;
|
|
2914
|
+
/**
|
|
2915
|
+
* 期望的类型或约束
|
|
2916
|
+
*/
|
|
2917
|
+
expected: string;
|
|
2918
|
+
};
|
|
2919
|
+
/**
|
|
2920
|
+
* 验证错误类型
|
|
2921
|
+
*
|
|
2922
|
+
* 包含验证失败的详细信息
|
|
2923
|
+
*/
|
|
2924
|
+
type ValidationError = {
|
|
2925
|
+
/**
|
|
2926
|
+
* 错误码
|
|
2927
|
+
*/
|
|
2928
|
+
code: 'VALIDATION_ERROR';
|
|
2929
|
+
/**
|
|
2930
|
+
* 错误消息
|
|
2931
|
+
*/
|
|
2932
|
+
message: string;
|
|
2933
|
+
/**
|
|
2934
|
+
* 字段级错误详情
|
|
2935
|
+
*/
|
|
2936
|
+
details: ValidationErrorDetail[];
|
|
2937
|
+
};
|
|
2938
|
+
/**
|
|
2939
|
+
* 验证结果类型
|
|
2940
|
+
*
|
|
2941
|
+
* 包含验证成功后的解析数据或验证失败的错误信息
|
|
2942
|
+
*
|
|
2943
|
+
* @typeParam TRoute - 路由定义类型
|
|
2944
|
+
*/
|
|
2945
|
+
type ValidationResult<TRoute extends RouteDefinition> = {
|
|
2946
|
+
/**
|
|
2947
|
+
* 验证是否成功
|
|
2948
|
+
*/
|
|
2949
|
+
success: boolean;
|
|
2950
|
+
/**
|
|
2951
|
+
* 解析后的路径参数,验证成功时存在
|
|
2952
|
+
*/
|
|
2953
|
+
params?: InferRouteParams<TRoute>;
|
|
2954
|
+
/**
|
|
2955
|
+
* 解析后的查询参数,验证成功时存在
|
|
2956
|
+
*/
|
|
2957
|
+
query?: InferRouteQuery<TRoute>;
|
|
2958
|
+
/**
|
|
2959
|
+
* 解析后的请求体,验证成功时存在
|
|
2960
|
+
*/
|
|
2961
|
+
body?: InferRouteBody<TRoute>;
|
|
2962
|
+
/**
|
|
2963
|
+
* 验证错误,验证失败时存在
|
|
2964
|
+
*/
|
|
2965
|
+
error?: ValidationError;
|
|
2966
|
+
};
|
|
2967
|
+
/**
|
|
2968
|
+
* 待验证的请求数据
|
|
2969
|
+
*/
|
|
2970
|
+
type RequestDataToValidate = {
|
|
2971
|
+
/**
|
|
2972
|
+
* 路径参数
|
|
2973
|
+
*/
|
|
2974
|
+
params?: Record<string, string>;
|
|
2975
|
+
/**
|
|
2976
|
+
* 查询参数
|
|
2977
|
+
*/
|
|
2978
|
+
query?: Record<string, string | string[]>;
|
|
2979
|
+
/**
|
|
2980
|
+
* 请求体
|
|
2981
|
+
*/
|
|
2982
|
+
body?: unknown;
|
|
2983
|
+
};
|
|
2984
|
+
/**
|
|
2985
|
+
* 从 ZodError 中提取验证错误详情
|
|
2986
|
+
*
|
|
2987
|
+
* @param zodError - Zod 验证错误
|
|
2988
|
+
* @param prefix - 字段路径前缀
|
|
2989
|
+
* @returns 验证错误详情数组
|
|
2990
|
+
*/
|
|
2991
|
+
declare function extractErrorDetails(zodError: ZodError, prefix?: string): ValidationErrorDetail[];
|
|
2992
|
+
/**
|
|
2993
|
+
* Schema 验证成功结果
|
|
2994
|
+
*
|
|
2995
|
+
* @typeParam T - 解析后的数据类型
|
|
2996
|
+
*/
|
|
2997
|
+
type SchemaValidationSuccess<T> = {
|
|
2998
|
+
/**
|
|
2999
|
+
* 验证成功标记
|
|
3000
|
+
*/
|
|
3001
|
+
success: true;
|
|
3002
|
+
/**
|
|
3003
|
+
* 解析后的数据
|
|
3004
|
+
*/
|
|
3005
|
+
data: T;
|
|
3006
|
+
};
|
|
3007
|
+
/**
|
|
3008
|
+
* Schema 验证失败结果
|
|
3009
|
+
*/
|
|
3010
|
+
type SchemaValidationFailure = {
|
|
3011
|
+
/**
|
|
3012
|
+
* 验证失败标记
|
|
3013
|
+
*/
|
|
3014
|
+
success: false;
|
|
3015
|
+
/**
|
|
3016
|
+
* 验证错误详情列表
|
|
3017
|
+
*/
|
|
3018
|
+
details: ValidationErrorDetail[];
|
|
3019
|
+
};
|
|
3020
|
+
/**
|
|
3021
|
+
* Schema 验证结果
|
|
3022
|
+
*
|
|
3023
|
+
* @typeParam T - 解析后的数据类型
|
|
3024
|
+
*/
|
|
3025
|
+
type SchemaValidationResult<T> = SchemaValidationSuccess<T> | SchemaValidationFailure;
|
|
3026
|
+
/**
|
|
3027
|
+
* 验证请求
|
|
3028
|
+
*
|
|
3029
|
+
* 从 RouteDefinition 中提取 Schema 并验证请求的 params / query / body
|
|
3030
|
+
*
|
|
3031
|
+
* @example
|
|
3032
|
+
* ```typescript
|
|
3033
|
+
* import { validateRequest, defineRoute, z } from '@longzai-intelligence-transport/http';
|
|
3034
|
+
*
|
|
3035
|
+
* const userRoute = defineRoute({
|
|
3036
|
+
* method: 'POST',
|
|
3037
|
+
* path: '/users/:id',
|
|
3038
|
+
* params: z.object({ id: z.string().uuid() }),
|
|
3039
|
+
* query: z.object({ include: z.enum(['profile', 'settings']).optional() }),
|
|
3040
|
+
* body: z.object({ name: z.string(), email: z.string().email() }),
|
|
3041
|
+
* response: z.object({ id: z.string(), name: z.string() }),
|
|
3042
|
+
* });
|
|
3043
|
+
*
|
|
3044
|
+
* const result = validateRequest(userRoute, {
|
|
3045
|
+
* params: { id: 'invalid-uuid' },
|
|
3046
|
+
* body: { name: 'Test', email: 'invalid-email' },
|
|
3047
|
+
* });
|
|
3048
|
+
*
|
|
3049
|
+
* if (!result.success) {
|
|
3050
|
+
* console.log(result.error.details);
|
|
3051
|
+
* // [{ path: 'params.id', message: '...', ... }, { path: 'body.email', message: '...', ... }]
|
|
3052
|
+
* }
|
|
3053
|
+
* ```;
|
|
3054
|
+
*
|
|
3055
|
+
* @typeParam TRoute - 路由定义类型
|
|
3056
|
+
* @param route - 路由定义
|
|
3057
|
+
* @param request - 待验证的请求数据
|
|
3058
|
+
* @returns 验证结果
|
|
3059
|
+
* @throws {@link Error} 当验证结果创建失败时抛出错误
|
|
3060
|
+
*/
|
|
3061
|
+
declare function validateRequest<TRoute extends RouteDefinition>(route: TRoute, request: RequestDataToValidate): ValidationResult<TRoute>;
|
|
3062
|
+
/**
|
|
3063
|
+
* 从 Zod 验证错误创建结构化 API 错误响应
|
|
3064
|
+
*
|
|
3065
|
+
* @example
|
|
3066
|
+
* ```typescript
|
|
3067
|
+
* import { createValidationErrorResponse } from '@longzai-intelligence-transport/http';
|
|
3068
|
+
* import * as z from 'zod';
|
|
3069
|
+
*
|
|
3070
|
+
* const schema = z.object({ name: z.string() });
|
|
3071
|
+
* const result = schema.safeParse({ name: 123 });
|
|
3072
|
+
*
|
|
3073
|
+
* if (!result.success) {
|
|
3074
|
+
* const response = createValidationErrorResponse(result.error);
|
|
3075
|
+
* // { success: false, error: { code: 'VALIDATION_ERROR', message: '参数验证失败', details: [...] } }
|
|
3076
|
+
* }
|
|
3077
|
+
* ```;
|
|
3078
|
+
*
|
|
3079
|
+
* @param zodError - Zod 验证错误
|
|
3080
|
+
* @param message - 自定义错误消息,默认为"参数验证失败"
|
|
3081
|
+
* @returns 符合 ApiResponse 格式的错误响应
|
|
3082
|
+
*/
|
|
3083
|
+
declare function createValidationErrorResponse(zodError: ZodError, message?: string): ApiResponse<never>;
|
|
3084
|
+
/**
|
|
3085
|
+
* 从 ValidationError 创建 API 错误响应
|
|
3086
|
+
*
|
|
3087
|
+
* @param validationError - 验证错误
|
|
3088
|
+
* @returns 符合 ApiResponse 格式的错误响应
|
|
3089
|
+
*/
|
|
3090
|
+
declare function createValidationErrorResponseFromError(validationError: ValidationError): ApiResponse<never>;
|
|
3091
|
+
//#endregion
|
|
3092
|
+
//#region src/types.d.ts
|
|
3093
|
+
/**
|
|
3094
|
+
* 路由处理器类型
|
|
3095
|
+
*
|
|
3096
|
+
* 描述服务端路由的处理函数签名
|
|
3097
|
+
*
|
|
3098
|
+
* @typeParam T - 路由定义类型
|
|
3099
|
+
*/
|
|
3100
|
+
type RouteHandler<T extends RouteDefinition> = (context: {
|
|
3101
|
+
/**
|
|
3102
|
+
* 路径参数
|
|
3103
|
+
*/
|
|
3104
|
+
params?: InferRouteParams<T>;
|
|
3105
|
+
/**
|
|
3106
|
+
* 查询参数
|
|
3107
|
+
*/
|
|
3108
|
+
query?: InferRouteQuery<T>;
|
|
3109
|
+
/**
|
|
3110
|
+
* 请求体
|
|
3111
|
+
*/
|
|
3112
|
+
body?: InferRouteBody<T>;
|
|
3113
|
+
/**
|
|
3114
|
+
* 请求头
|
|
3115
|
+
*/
|
|
3116
|
+
headers?: Record<string, string>;
|
|
3117
|
+
}) => Promise<InferRouteResponse<T>>;
|
|
3118
|
+
/**
|
|
3119
|
+
* 路由配置类型
|
|
3120
|
+
*
|
|
3121
|
+
* 将路由定义与处理器绑定
|
|
3122
|
+
*
|
|
3123
|
+
* @typeParam T - 路由定义类型
|
|
3124
|
+
*/
|
|
3125
|
+
type RouteConfig<T extends RouteDefinition> = {
|
|
3126
|
+
/**
|
|
3127
|
+
* 路由定义
|
|
3128
|
+
*/
|
|
3129
|
+
route: T;
|
|
3130
|
+
/**
|
|
3131
|
+
* 路由处理器
|
|
3132
|
+
*/
|
|
3133
|
+
handler: RouteHandler<T>;
|
|
3134
|
+
};
|
|
3135
|
+
//#endregion
|
|
3136
|
+
export { type ApiCompactPaginatedListData, ApiCompactPaginatedListDataSchema, type ApiError, type ApiErrorResponse, ApiErrorResponseSchema, ApiErrorSchema, type ApiFailResponse, type ApiFunctions, type ApiListData, ApiListDataSchema, ApiListDataUtil, type ApiPaginatedListData, ApiPaginatedListDataSchema, type ApiResponse, ApiResponseSchema, ApiResponseUtil, type ApiSuccessResponse, type ApiVersion, type ArrayElement, type AuthInterceptorConfig, type AuthStrategy, type AwaitedData, type AxiosAdapterConfig, type CreateApiFunction, type CreateDeleteFunction, type CreateGetFunction, type CreatePostFunction, type CreateUpdateFunction, type CsrfInterceptorConfig, type CsrfProvider, type CursorPaginatedResult, type CursorPaginationParams, CursorPaginationParamsSchema, DEFAULT_RETRY_STATUS_CODES, type DateRangeQuery, DateRangeQuerySchema, type DeepPartial, type DeepReadonly, type DeepRequired, ERROR_HTTP_STATUS, ERROR_MESSAGES, type EmptyResponse, EmptyResponseSchema, ErrorCode, type ErrorCodeConfig, ErrorCodeSchema, type ExtractData, type FilterQuery, FilterQuerySchema, type FormDataConvertConfig, type HttpAdapter, type HttpClient, type HttpClientConfig, type HttpMethod, type HttpPaginationConfig, type IdParams, IdParamsSchema, type InferRouteBody, type InferRouteFullResponse, type InferRouteItem, type InferRouteParams, type InferRouteQuery, type InferRouteResponse, type InferRouteReturn, type InterceptorExecutorConfig, type LoggingInterceptorConfig, type Merge, type MockRequest, type MockRequestContext, type NonNullableData, type ObjectKeys, type ObjectValues, type OffsetPaginatedResult, type OffsetPaginationParams, OffsetPaginationParamsSchema, type OmitByValue, type OptionalKeyOf, type OptionalKeys, type PaginatedResult, type PaginationParams, PaginationParamsSchema, type PaginationQuery, PaginationQuerySchema, type PickByValue, type RequestConfig, type RequestDataToValidate, type RequestInterceptor, type RequestInterceptorContext, type RequiredKeyOf, type RequiredKeys, type ResponseInterceptor, type ResponseInterceptorContext, type ResponseTransformer, type RetryConfig, type ReturnDataType, type RouteConfig, type RouteDefineConfig, type RouteDefineResult, type RouteDefinition, type RouteGroup, type RouteGroupConfig, type RouteHandler, type RouteMockRequestOptions, type RouteResponseBuilder, type SchemaValidationFailure, type SchemaValidationResult, type SchemaValidationSuccess, type SearchQuery, SearchQuerySchema, type TaroAdapterConfig, type TokenProvider, type UnwrapApiListData, type UnwrapApiPaginatedListData, type UnwrapApiResponse, type ValidationError, type ValidationErrorDetail, type ValidationInterceptorConfig, type ValidationResult, type VersionedPrefix, buildPath, buildQuery, calculateOffset, calculateTotalPages, concatPath, createApiClientFactory, createAuthStrategyInterceptor, createAuthTokenInterceptor, createAxiosAdapter, createAxiosInstance, createBearerAuthStrategy, createConfigurableMockHttpClient, createCookieAuthStrategy, createCsrfInterceptor, createCustomAuthStrategy, createDelayedMockHttpClient, createErrorCodeSchema, createErrorMockHttpClient, createExecutorConfigFromClientConfig, createFilterQuerySchema, createHttpClient, createHttpPaginationSchema, createInterceptorExecutor, createLoggingInterceptor, createLoggingRequestInterceptor, createLoggingResponseInterceptor, createMockHttpClient, createNoneAuthStrategy, createPaginatedResult, createRequestInterceptorsFromConfig, createResponseInterceptorsFromConfig, createResponseTransformerInterceptor, createRetryInterceptor, createRouteMock, createRouteResponseBuilder, createTypedEmpty, createTypedResponse, createValidationErrorResponse, createValidationErrorResponseFromError, createValidationInterceptor, defaultLogger, defineRoute, defineRouteGroup, exponentialBackoff, extractErrorDetails, getErrorMessage, getHttpStatus, isBlob, isFile, isFormDataContentType, isLegacyConfig, isRecord, isType, normalizePagination, objectToFormData, setHttpClientConfig, unwrapResult, validateRequest, warnDeprecatedConfig };
|