@lark-apaas/http-client 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.
@@ -0,0 +1,323 @@
1
+ /**
2
+ * 拦截器管理器(模仿 Axios 的 InterceptorManager)
3
+ */
4
+ declare class InterceptorManager<T> {
5
+ private interceptors;
6
+ /**
7
+ * 添加拦截器
8
+ * @returns 拦截器 ID,用于后续移除
9
+ */
10
+ use(onFulfilled?: any, onRejected?: any): number;
11
+ /**
12
+ * 移除拦截器
13
+ */
14
+ eject(id: number): void;
15
+ /**
16
+ * 清空所有拦截器
17
+ */
18
+ clear(): void;
19
+ /**
20
+ * 遍历所有拦截器
21
+ */
22
+ forEach(fn: (interceptor: T) => void): void;
23
+ }
24
+
25
+ interface CustomClaims {
26
+ tenant_id?: number;
27
+ user_id?: string;
28
+ app_id?: string;
29
+ app_env?: string;
30
+ sandbox_id?: string;
31
+ access_key: string;
32
+ }
33
+ interface JWTClaims extends CustomClaims {
34
+ iss: string;
35
+ iat: number;
36
+ nbf: number;
37
+ exp: number;
38
+ jti: string;
39
+ [key: string]: any;
40
+ }
41
+ interface JWTConfig {
42
+ accessKey: string;
43
+ secretKey: string;
44
+ expireTimeMs: number;
45
+ }
46
+ interface JWTVerifyOptions {
47
+ /**
48
+ * 时钟容差(秒),用于处理服务器时间不同步的情况
49
+ * 默认 60 秒
50
+ */
51
+ clockTolerance?: number;
52
+ /**
53
+ * 是否跳过过期验证(仅用于调试)
54
+ * 默认 false
55
+ */
56
+ skipExpiration?: boolean;
57
+ }
58
+ declare const DEFAULT_JWT_EXPIRE_TIME_MS: number;
59
+ declare const DEFAULT_CLOCK_TOLERANCE_SEC = 60;
60
+ declare function generateJWTToken(customClaims: CustomClaims, config: JWTConfig): string;
61
+ declare function parseJWTTokenWithVerify(tokenString: string, config: JWTConfig, options?: JWTVerifyOptions): JWTClaims;
62
+
63
+ interface JWTManagerConfig extends JWTConfig {
64
+ /**
65
+ * 在过期前多久刷新 token(毫秒)
66
+ * 默认 5 分钟
67
+ */
68
+ refreshBeforeMs?: number;
69
+ }
70
+ /**
71
+ * JWT Token 管理器,负责 token 的生成、缓存和自动刷新
72
+ *
73
+ * 缓存策略:
74
+ * - 基于 claims 的哈希值作为缓存 key(支持多租户+多用户)
75
+ * - 在 token 过期前 refreshBeforeMs 时间内自动刷新
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const manager = new JWTTokenManager({
80
+ * accessKey: 'your-access-key',
81
+ * secretKey: 'your-secret-key',
82
+ * expireTimeMs: 30 * 60 * 1000,
83
+ * refreshBeforeMs: 5 * 60 * 1000,
84
+ * });
85
+ *
86
+ * // 获取 token(会自动缓存)
87
+ * const token = manager.getToken({
88
+ * access_key: 'your-access-key',
89
+ * tenant_id: 1001,
90
+ * user_id: 'user123',
91
+ * });
92
+ * ```
93
+ */
94
+ declare class JWTTokenManager {
95
+ private cache;
96
+ private config;
97
+ constructor(config: JWTManagerConfig);
98
+ /**
99
+ * 获取 JWT token,优先使用缓存
100
+ *
101
+ * 如果缓存的 token 即将过期(距离过期时间小于 refreshBeforeMs),
102
+ * 则会生成新的 token 并更新缓存
103
+ *
104
+ * @param claims - JWT claims
105
+ * @returns JWT token 字符串
106
+ */
107
+ getToken(claims: CustomClaims): string;
108
+ /**
109
+ * 清除所有缓存的 token
110
+ */
111
+ clearCache(): void;
112
+ /**
113
+ * 清除特定 claims 的缓存
114
+ *
115
+ * @param claims - 要清除的 claims
116
+ */
117
+ clearCacheFor(claims: CustomClaims): void;
118
+ /**
119
+ * 生成缓存 key(基于关键的 claims 字段)
120
+ *
121
+ * 使用稳定的字段顺序确保相同 claims 生成相同 key
122
+ *
123
+ * @private
124
+ */
125
+ private getCacheKey;
126
+ /**
127
+ * 获取缓存统计信息(用于监控和调试)
128
+ *
129
+ * @returns 缓存统计信息
130
+ */
131
+ getCacheStats(): {
132
+ total: number;
133
+ valid: number;
134
+ expired: number;
135
+ };
136
+ }
137
+
138
+ type PlatformClaims = Omit<CustomClaims, 'access_key'>;
139
+ interface PlatformPluginOptions {
140
+ enabled?: boolean;
141
+ baseURL?: string;
142
+ domainEnv?: string;
143
+ accessKeyEnv?: string;
144
+ secretKeyEnv?: string;
145
+ accessKey?: string;
146
+ secretKey?: string;
147
+ expireTimeMs?: number;
148
+ refreshBeforeMs?: number;
149
+ defaultClaims?: PlatformClaims;
150
+ }
151
+ interface PlatformRequestAuthConfig {
152
+ customClaims?: PlatformClaims;
153
+ }
154
+ declare function resolvePlatformBaseURL(options?: PlatformPluginOptions): string | undefined;
155
+ type RequestInterceptorManager = {
156
+ use: (onFulfilled?: RequestInterceptor['onFulfilled'], onRejected?: RequestInterceptor['onRejected']) => number;
157
+ eject: (id: number) => void;
158
+ };
159
+ interface InterceptorHost {
160
+ request: RequestInterceptorManager;
161
+ }
162
+ declare function registerPlatformPlugin(interceptors: InterceptorHost, options: PlatformPluginOptions): JWTTokenManager | undefined;
163
+
164
+ /**
165
+ * 清理后的请求配置(移除敏感信息)
166
+ */
167
+ interface SafeRequestConfig extends Omit<RequestConfig, 'headers'> {
168
+ headers?: Record<string, string>;
169
+ }
170
+ /**
171
+ * HTTP 错误对象
172
+ *
173
+ * 注意:为了安全考虑,error.config 中的敏感 headers (如 Authorization, x-api-key)
174
+ * 会被替换为 '[REDACTED]'
175
+ */
176
+ declare class HttpError extends Error {
177
+ readonly isHttpError: boolean;
178
+ response: Response | undefined;
179
+ config: SafeRequestConfig;
180
+ constructor(response: Response | undefined, config: RequestConfig, message?: string);
181
+ }
182
+ interface RequestConfig extends RequestInit {
183
+ url?: string;
184
+ params?: Record<string, any>;
185
+ timeout?: number;
186
+ baseURL?: string;
187
+ platformAuth?: PlatformRequestAuthConfig;
188
+ }
189
+ interface SecurityConfig {
190
+ /**
191
+ * 允许的 URL 协议白名单
192
+ * 默认: null (不限制)
193
+ * 设置为 ['http:', 'https:'] 可限制只允许 HTTP/HTTPS
194
+ */
195
+ allowedProtocols?: string[] | null;
196
+ /**
197
+ * 最大响应体大小(字节)
198
+ * 默认: 0 (不限制)
199
+ * 设置为正数可限制响应体大小,防止内存耗尽攻击
200
+ */
201
+ maxResponseSize?: number;
202
+ /**
203
+ * 是否启用严格模式(启用所有安全检查)
204
+ * 默认: false
205
+ * 启用后会自动设置:
206
+ * - allowedProtocols = ['http:', 'https:']
207
+ * - maxResponseSize = 50MB
208
+ */
209
+ strictMode?: boolean;
210
+ }
211
+ interface HttpClientConfig extends RequestConfig {
212
+ platform?: PlatformPluginOptions;
213
+ security?: SecurityConfig;
214
+ }
215
+ /**
216
+ * 请求拦截器函数
217
+ */
218
+ type RequestInterceptor = {
219
+ onFulfilled?: (config: RequestConfig) => RequestConfig | Promise<RequestConfig>;
220
+ onRejected?: (error: any) => any;
221
+ };
222
+ /**
223
+ * 响应拦截器函数(fetch 风格)
224
+ */
225
+ type ResponseInterceptor = {
226
+ onFulfilled?: (response: Response) => Response | Promise<Response>;
227
+ onRejected?: (error: any) => any;
228
+ };
229
+
230
+ /**
231
+ * 技术栈无关的 HTTP 客户端
232
+ *
233
+ * 设计理念:
234
+ * - 基于原生 fetch API,零依赖
235
+ * - 拦截器模式遵循 Axios 标准,AI 模型和开发者都熟悉
236
+ * - 可在任何 Node.js 环境使用(NestJS, Express, Koa, 纯 Node)
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * const client = new HttpClient({
241
+ * baseURL: 'https://api.example.com',
242
+ * timeout: 5000,
243
+ * });
244
+ *
245
+ * // 添加请求拦截器(类似 Axios)
246
+ * client.interceptors.request.use(
247
+ * config => {
248
+ * config.headers = config.headers || {};
249
+ * config.headers['Authorization'] = 'Bearer token';
250
+ * return config;
251
+ * },
252
+ * error => Promise.reject(error)
253
+ * );
254
+ *
255
+ * // 添加响应拦截器(类似 Axios)
256
+ * client.interceptors.response.use(
257
+ * response => {
258
+ * console.log('Response:', response.status);
259
+ * return response;
260
+ * },
261
+ * error => {
262
+ * if (error.response?.status === 401) {
263
+ * // 处理未授权
264
+ * }
265
+ * return Promise.reject(error);
266
+ * }
267
+ * );
268
+ *
269
+ * // 发起请求
270
+ * const response = await client.get('/users');
271
+ * console.log(response.data);
272
+ * ```
273
+ */
274
+ declare class HttpClient {
275
+ private defaultConfig;
276
+ private securityConfig;
277
+ /**
278
+ * 拦截器管理器(API 与 Axios 一致)
279
+ */
280
+ interceptors: {
281
+ request: InterceptorManager<RequestInterceptor>;
282
+ response: InterceptorManager<ResponseInterceptor>;
283
+ };
284
+ constructor(config?: HttpClientConfig);
285
+ /**
286
+ * GET 请求
287
+ */
288
+ get(url: string, config?: RequestConfig): Promise<Response>;
289
+ /**
290
+ * POST 请求
291
+ */
292
+ post(url: string, data?: any, config?: RequestConfig): Promise<Response>;
293
+ /**
294
+ * PUT 请求
295
+ */
296
+ put(url: string, data?: any, config?: RequestConfig): Promise<Response>;
297
+ /**
298
+ * DELETE 请求
299
+ */
300
+ delete(url: string, config?: RequestConfig): Promise<Response>;
301
+ /**
302
+ * PATCH 请求
303
+ */
304
+ patch(url: string, data?: any, config?: RequestConfig): Promise<Response>;
305
+ /**
306
+ * 核心请求方法(fetch 风格)
307
+ */
308
+ request(config: RequestConfig): Promise<Response>;
309
+ /**
310
+ * 执行请求拦截器链
311
+ */
312
+ private runRequestInterceptors;
313
+ /**
314
+ * 执行响应拦截器链
315
+ */
316
+ private runResponseInterceptors;
317
+ /**
318
+ * 构建完整 URL(包含 baseURL 和 query params)
319
+ */
320
+ private buildUrl;
321
+ }
322
+
323
+ export { type CustomClaims, DEFAULT_CLOCK_TOLERANCE_SEC, DEFAULT_JWT_EXPIRE_TIME_MS, HttpClient, type HttpClientConfig, HttpError, type JWTClaims, type JWTConfig, type JWTVerifyOptions, type PlatformClaims, type PlatformPluginOptions, type PlatformRequestAuthConfig, type RequestConfig, type RequestInterceptor, type ResponseInterceptor, type SafeRequestConfig, type SecurityConfig, generateJWTToken, parseJWTTokenWithVerify, registerPlatformPlugin, resolvePlatformBaseURL };
@@ -0,0 +1,323 @@
1
+ /**
2
+ * 拦截器管理器(模仿 Axios 的 InterceptorManager)
3
+ */
4
+ declare class InterceptorManager<T> {
5
+ private interceptors;
6
+ /**
7
+ * 添加拦截器
8
+ * @returns 拦截器 ID,用于后续移除
9
+ */
10
+ use(onFulfilled?: any, onRejected?: any): number;
11
+ /**
12
+ * 移除拦截器
13
+ */
14
+ eject(id: number): void;
15
+ /**
16
+ * 清空所有拦截器
17
+ */
18
+ clear(): void;
19
+ /**
20
+ * 遍历所有拦截器
21
+ */
22
+ forEach(fn: (interceptor: T) => void): void;
23
+ }
24
+
25
+ interface CustomClaims {
26
+ tenant_id?: number;
27
+ user_id?: string;
28
+ app_id?: string;
29
+ app_env?: string;
30
+ sandbox_id?: string;
31
+ access_key: string;
32
+ }
33
+ interface JWTClaims extends CustomClaims {
34
+ iss: string;
35
+ iat: number;
36
+ nbf: number;
37
+ exp: number;
38
+ jti: string;
39
+ [key: string]: any;
40
+ }
41
+ interface JWTConfig {
42
+ accessKey: string;
43
+ secretKey: string;
44
+ expireTimeMs: number;
45
+ }
46
+ interface JWTVerifyOptions {
47
+ /**
48
+ * 时钟容差(秒),用于处理服务器时间不同步的情况
49
+ * 默认 60 秒
50
+ */
51
+ clockTolerance?: number;
52
+ /**
53
+ * 是否跳过过期验证(仅用于调试)
54
+ * 默认 false
55
+ */
56
+ skipExpiration?: boolean;
57
+ }
58
+ declare const DEFAULT_JWT_EXPIRE_TIME_MS: number;
59
+ declare const DEFAULT_CLOCK_TOLERANCE_SEC = 60;
60
+ declare function generateJWTToken(customClaims: CustomClaims, config: JWTConfig): string;
61
+ declare function parseJWTTokenWithVerify(tokenString: string, config: JWTConfig, options?: JWTVerifyOptions): JWTClaims;
62
+
63
+ interface JWTManagerConfig extends JWTConfig {
64
+ /**
65
+ * 在过期前多久刷新 token(毫秒)
66
+ * 默认 5 分钟
67
+ */
68
+ refreshBeforeMs?: number;
69
+ }
70
+ /**
71
+ * JWT Token 管理器,负责 token 的生成、缓存和自动刷新
72
+ *
73
+ * 缓存策略:
74
+ * - 基于 claims 的哈希值作为缓存 key(支持多租户+多用户)
75
+ * - 在 token 过期前 refreshBeforeMs 时间内自动刷新
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const manager = new JWTTokenManager({
80
+ * accessKey: 'your-access-key',
81
+ * secretKey: 'your-secret-key',
82
+ * expireTimeMs: 30 * 60 * 1000,
83
+ * refreshBeforeMs: 5 * 60 * 1000,
84
+ * });
85
+ *
86
+ * // 获取 token(会自动缓存)
87
+ * const token = manager.getToken({
88
+ * access_key: 'your-access-key',
89
+ * tenant_id: 1001,
90
+ * user_id: 'user123',
91
+ * });
92
+ * ```
93
+ */
94
+ declare class JWTTokenManager {
95
+ private cache;
96
+ private config;
97
+ constructor(config: JWTManagerConfig);
98
+ /**
99
+ * 获取 JWT token,优先使用缓存
100
+ *
101
+ * 如果缓存的 token 即将过期(距离过期时间小于 refreshBeforeMs),
102
+ * 则会生成新的 token 并更新缓存
103
+ *
104
+ * @param claims - JWT claims
105
+ * @returns JWT token 字符串
106
+ */
107
+ getToken(claims: CustomClaims): string;
108
+ /**
109
+ * 清除所有缓存的 token
110
+ */
111
+ clearCache(): void;
112
+ /**
113
+ * 清除特定 claims 的缓存
114
+ *
115
+ * @param claims - 要清除的 claims
116
+ */
117
+ clearCacheFor(claims: CustomClaims): void;
118
+ /**
119
+ * 生成缓存 key(基于关键的 claims 字段)
120
+ *
121
+ * 使用稳定的字段顺序确保相同 claims 生成相同 key
122
+ *
123
+ * @private
124
+ */
125
+ private getCacheKey;
126
+ /**
127
+ * 获取缓存统计信息(用于监控和调试)
128
+ *
129
+ * @returns 缓存统计信息
130
+ */
131
+ getCacheStats(): {
132
+ total: number;
133
+ valid: number;
134
+ expired: number;
135
+ };
136
+ }
137
+
138
+ type PlatformClaims = Omit<CustomClaims, 'access_key'>;
139
+ interface PlatformPluginOptions {
140
+ enabled?: boolean;
141
+ baseURL?: string;
142
+ domainEnv?: string;
143
+ accessKeyEnv?: string;
144
+ secretKeyEnv?: string;
145
+ accessKey?: string;
146
+ secretKey?: string;
147
+ expireTimeMs?: number;
148
+ refreshBeforeMs?: number;
149
+ defaultClaims?: PlatformClaims;
150
+ }
151
+ interface PlatformRequestAuthConfig {
152
+ customClaims?: PlatformClaims;
153
+ }
154
+ declare function resolvePlatformBaseURL(options?: PlatformPluginOptions): string | undefined;
155
+ type RequestInterceptorManager = {
156
+ use: (onFulfilled?: RequestInterceptor['onFulfilled'], onRejected?: RequestInterceptor['onRejected']) => number;
157
+ eject: (id: number) => void;
158
+ };
159
+ interface InterceptorHost {
160
+ request: RequestInterceptorManager;
161
+ }
162
+ declare function registerPlatformPlugin(interceptors: InterceptorHost, options: PlatformPluginOptions): JWTTokenManager | undefined;
163
+
164
+ /**
165
+ * 清理后的请求配置(移除敏感信息)
166
+ */
167
+ interface SafeRequestConfig extends Omit<RequestConfig, 'headers'> {
168
+ headers?: Record<string, string>;
169
+ }
170
+ /**
171
+ * HTTP 错误对象
172
+ *
173
+ * 注意:为了安全考虑,error.config 中的敏感 headers (如 Authorization, x-api-key)
174
+ * 会被替换为 '[REDACTED]'
175
+ */
176
+ declare class HttpError extends Error {
177
+ readonly isHttpError: boolean;
178
+ response: Response | undefined;
179
+ config: SafeRequestConfig;
180
+ constructor(response: Response | undefined, config: RequestConfig, message?: string);
181
+ }
182
+ interface RequestConfig extends RequestInit {
183
+ url?: string;
184
+ params?: Record<string, any>;
185
+ timeout?: number;
186
+ baseURL?: string;
187
+ platformAuth?: PlatformRequestAuthConfig;
188
+ }
189
+ interface SecurityConfig {
190
+ /**
191
+ * 允许的 URL 协议白名单
192
+ * 默认: null (不限制)
193
+ * 设置为 ['http:', 'https:'] 可限制只允许 HTTP/HTTPS
194
+ */
195
+ allowedProtocols?: string[] | null;
196
+ /**
197
+ * 最大响应体大小(字节)
198
+ * 默认: 0 (不限制)
199
+ * 设置为正数可限制响应体大小,防止内存耗尽攻击
200
+ */
201
+ maxResponseSize?: number;
202
+ /**
203
+ * 是否启用严格模式(启用所有安全检查)
204
+ * 默认: false
205
+ * 启用后会自动设置:
206
+ * - allowedProtocols = ['http:', 'https:']
207
+ * - maxResponseSize = 50MB
208
+ */
209
+ strictMode?: boolean;
210
+ }
211
+ interface HttpClientConfig extends RequestConfig {
212
+ platform?: PlatformPluginOptions;
213
+ security?: SecurityConfig;
214
+ }
215
+ /**
216
+ * 请求拦截器函数
217
+ */
218
+ type RequestInterceptor = {
219
+ onFulfilled?: (config: RequestConfig) => RequestConfig | Promise<RequestConfig>;
220
+ onRejected?: (error: any) => any;
221
+ };
222
+ /**
223
+ * 响应拦截器函数(fetch 风格)
224
+ */
225
+ type ResponseInterceptor = {
226
+ onFulfilled?: (response: Response) => Response | Promise<Response>;
227
+ onRejected?: (error: any) => any;
228
+ };
229
+
230
+ /**
231
+ * 技术栈无关的 HTTP 客户端
232
+ *
233
+ * 设计理念:
234
+ * - 基于原生 fetch API,零依赖
235
+ * - 拦截器模式遵循 Axios 标准,AI 模型和开发者都熟悉
236
+ * - 可在任何 Node.js 环境使用(NestJS, Express, Koa, 纯 Node)
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * const client = new HttpClient({
241
+ * baseURL: 'https://api.example.com',
242
+ * timeout: 5000,
243
+ * });
244
+ *
245
+ * // 添加请求拦截器(类似 Axios)
246
+ * client.interceptors.request.use(
247
+ * config => {
248
+ * config.headers = config.headers || {};
249
+ * config.headers['Authorization'] = 'Bearer token';
250
+ * return config;
251
+ * },
252
+ * error => Promise.reject(error)
253
+ * );
254
+ *
255
+ * // 添加响应拦截器(类似 Axios)
256
+ * client.interceptors.response.use(
257
+ * response => {
258
+ * console.log('Response:', response.status);
259
+ * return response;
260
+ * },
261
+ * error => {
262
+ * if (error.response?.status === 401) {
263
+ * // 处理未授权
264
+ * }
265
+ * return Promise.reject(error);
266
+ * }
267
+ * );
268
+ *
269
+ * // 发起请求
270
+ * const response = await client.get('/users');
271
+ * console.log(response.data);
272
+ * ```
273
+ */
274
+ declare class HttpClient {
275
+ private defaultConfig;
276
+ private securityConfig;
277
+ /**
278
+ * 拦截器管理器(API 与 Axios 一致)
279
+ */
280
+ interceptors: {
281
+ request: InterceptorManager<RequestInterceptor>;
282
+ response: InterceptorManager<ResponseInterceptor>;
283
+ };
284
+ constructor(config?: HttpClientConfig);
285
+ /**
286
+ * GET 请求
287
+ */
288
+ get(url: string, config?: RequestConfig): Promise<Response>;
289
+ /**
290
+ * POST 请求
291
+ */
292
+ post(url: string, data?: any, config?: RequestConfig): Promise<Response>;
293
+ /**
294
+ * PUT 请求
295
+ */
296
+ put(url: string, data?: any, config?: RequestConfig): Promise<Response>;
297
+ /**
298
+ * DELETE 请求
299
+ */
300
+ delete(url: string, config?: RequestConfig): Promise<Response>;
301
+ /**
302
+ * PATCH 请求
303
+ */
304
+ patch(url: string, data?: any, config?: RequestConfig): Promise<Response>;
305
+ /**
306
+ * 核心请求方法(fetch 风格)
307
+ */
308
+ request(config: RequestConfig): Promise<Response>;
309
+ /**
310
+ * 执行请求拦截器链
311
+ */
312
+ private runRequestInterceptors;
313
+ /**
314
+ * 执行响应拦截器链
315
+ */
316
+ private runResponseInterceptors;
317
+ /**
318
+ * 构建完整 URL(包含 baseURL 和 query params)
319
+ */
320
+ private buildUrl;
321
+ }
322
+
323
+ export { type CustomClaims, DEFAULT_CLOCK_TOLERANCE_SEC, DEFAULT_JWT_EXPIRE_TIME_MS, HttpClient, type HttpClientConfig, HttpError, type JWTClaims, type JWTConfig, type JWTVerifyOptions, type PlatformClaims, type PlatformPluginOptions, type PlatformRequestAuthConfig, type RequestConfig, type RequestInterceptor, type ResponseInterceptor, type SafeRequestConfig, type SecurityConfig, generateJWTToken, parseJWTTokenWithVerify, registerPlatformPlugin, resolvePlatformBaseURL };