axios-wrapper-pro 1.0.4 → 1.0.5

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/dist/index.mjs ADDED
@@ -0,0 +1,339 @@
1
+ // src/index.ts
2
+ import axios2 from "axios";
3
+
4
+ // src/utils.ts
5
+ import axios from "axios";
6
+ function isFunction(variable) {
7
+ return typeof variable === "function";
8
+ }
9
+ function sleep(ms) {
10
+ return new Promise((resolve) => setTimeout(resolve, ms));
11
+ }
12
+ function isCancel(error) {
13
+ return axios.isCancel(error);
14
+ }
15
+
16
+ // src/config.ts
17
+ var DEFAULT_CONFIG = {
18
+ baseURL: "",
19
+ timeout: 1e4,
20
+ headers: {
21
+ "Content-Type": "application/json;charset=utf-8"
22
+ }
23
+ };
24
+ var DEFAULT_RETRY_CONFIG = {
25
+ count: 0,
26
+ delay: 1e3,
27
+ condition: (error) => {
28
+ var _a;
29
+ if (isCancel(error)) return false;
30
+ if (!(error == null ? void 0 : error.response)) return true;
31
+ return ((_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status) >= 500;
32
+ }
33
+ };
34
+ var DEFAULT_INTERCEPTOR = {
35
+ request: (config) => config,
36
+ requestError: (error) => Promise.reject(error),
37
+ response: (response) => response,
38
+ responseError: (error) => Promise.reject(error)
39
+ };
40
+
41
+ // src/index.ts
42
+ var AxiosWrapperPro = class {
43
+ constructor(options = {}) {
44
+ this._abortControllers = /* @__PURE__ */ new Map();
45
+ this._retryConfig = {
46
+ ...DEFAULT_RETRY_CONFIG,
47
+ ...(options == null ? void 0 : options.retry) || {}
48
+ };
49
+ this._paramsSerializer = isFunction(options.paramsSerializer) ? options.paramsSerializer : null;
50
+ const axiosConfig = {
51
+ ...DEFAULT_CONFIG,
52
+ ...options.baseURL && { baseURL: options.baseURL },
53
+ ...options.timeout && { timeout: options.timeout },
54
+ headers: { ...DEFAULT_CONFIG.headers, ...options.headers }
55
+ };
56
+ if (this._paramsSerializer) {
57
+ axiosConfig.paramsSerializer = this._paramsSerializer;
58
+ }
59
+ this._instance = axios2.create(axiosConfig);
60
+ this._interceptorConfig = options.interceptors || {};
61
+ this._initRequestInterceptors();
62
+ this._initResponseInterceptors();
63
+ }
64
+ /**
65
+ * 获取拦截器配置,未配置的使用默认值
66
+ * @returns {InterceptorConfig} 完整的拦截器配置
67
+ */
68
+ _getInterceptors() {
69
+ const { request, requestError, response, responseError } = this._interceptorConfig;
70
+ return {
71
+ request: isFunction(request) ? request : DEFAULT_INTERCEPTOR.request,
72
+ requestError: isFunction(requestError) ? requestError : DEFAULT_INTERCEPTOR.requestError,
73
+ response: isFunction(response) ? response : DEFAULT_INTERCEPTOR.response,
74
+ responseError: isFunction(responseError) ? responseError : DEFAULT_INTERCEPTOR.responseError
75
+ };
76
+ }
77
+ /**
78
+ * 初始化请求拦截器
79
+ */
80
+ _initRequestInterceptors() {
81
+ const { request, requestError } = this._getInterceptors();
82
+ this._requestInterceptorId = this._instance.interceptors.request.use(request, requestError);
83
+ }
84
+ /**
85
+ * 初始化响应拦截器
86
+ */
87
+ _initResponseInterceptors() {
88
+ const { response, responseError } = this._getInterceptors();
89
+ this._responseInterceptorId = this._instance.interceptors.response.use(
90
+ (res) => {
91
+ const key = res.config._requestKey;
92
+ key && this._abortControllers.delete(key);
93
+ return response(res);
94
+ },
95
+ (error) => {
96
+ var _a;
97
+ const key = (_a = error.config) == null ? void 0 : _a._requestKey;
98
+ key && this._abortControllers.delete(key);
99
+ return responseError(error);
100
+ }
101
+ );
102
+ }
103
+ /**
104
+ * 设置请求拦截器,移除旧拦截器,更新拦截器配置,重新初始化拦截器
105
+ * @param {InterceptorConfig["request"]} interceptor 拦截器
106
+ * @param {InterceptorConfig["requestError"]} errorInterceptor 错误拦截器
107
+ */
108
+ setRequestInterceptor(interceptor, errorInterceptor) {
109
+ if (this._requestInterceptorId !== void 0) {
110
+ this._instance.interceptors.request.eject(this._requestInterceptorId);
111
+ }
112
+ this._interceptorConfig.request = interceptor;
113
+ this._interceptorConfig.requestError = errorInterceptor;
114
+ this._initRequestInterceptors();
115
+ }
116
+ /**
117
+ * 设置响应拦截器,移除旧拦截器,更新拦截器配置,重新初始化拦截器
118
+ * @param {InterceptorConfig["response"]} interceptor 拦截器
119
+ * @param {InterceptorConfig["responseError"]} errorInterceptor 错误拦截器
120
+ */
121
+ setResponseInterceptor(interceptor, errorInterceptor) {
122
+ if (this._responseInterceptorId !== void 0) {
123
+ this._instance.interceptors.response.eject(this._responseInterceptorId);
124
+ }
125
+ this._interceptorConfig.response = interceptor;
126
+ this._interceptorConfig.responseError = errorInterceptor;
127
+ this._initResponseInterceptors();
128
+ }
129
+ /**
130
+ * 设置取消控制器
131
+ * @param {AxiosRequestConfig} config 请求配置
132
+ * @param {RequestKey} customKey 自定义key
133
+ * @returns {InternalAxiosRequestConfig} 处理后的配置
134
+ */
135
+ _setupAbortController(config, customKey) {
136
+ const key = customKey != null ? customKey : this._generateRequestKey(config);
137
+ this.cancelRequest(key);
138
+ const controller = new AbortController();
139
+ this._abortControllers.set(key, controller);
140
+ return { ...config, signal: controller.signal, _requestKey: key };
141
+ }
142
+ /**
143
+ * 生成请求唯一标识
144
+ * @param {AxiosRequestConfig} config 请求配置
145
+ * @returns {string} 请求唯一标识
146
+ */
147
+ _generateRequestKey(config) {
148
+ const method = (config.method || "GET").toUpperCase();
149
+ const url = config.url || "";
150
+ const params = config.params ? { ...config.params } : null;
151
+ if (params == null ? void 0 : params._t) {
152
+ delete params._t;
153
+ }
154
+ const serializer = isFunction(config.paramsSerializer) ? config.paramsSerializer : this._paramsSerializer;
155
+ let paramsStr = "";
156
+ if (params) {
157
+ paramsStr = serializer ? serializer(params) : this._stableStringify(params);
158
+ }
159
+ let dataStr = "";
160
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && config.data) {
161
+ dataStr = typeof config.data === "string" ? config.data : this._stableStringify(config.data);
162
+ }
163
+ return `${method}|${url}|${paramsStr}|${dataStr}`;
164
+ }
165
+ /**
166
+ * 稳定的JSON序列化,确保相同内容生成相同字符串
167
+ * @param {any} obj 待序列化对象
168
+ * @returns {string} 序列化后的字符串
169
+ */
170
+ _stableStringify(obj) {
171
+ if (obj === null || obj === void 0) {
172
+ return "";
173
+ }
174
+ if (Array.isArray(obj)) {
175
+ return "[" + obj.map((item) => this._stableStringify(item)).join(",") + "]";
176
+ }
177
+ if (typeof obj === "object") {
178
+ const sortedKeys = Object.keys(obj).sort();
179
+ const pairs = sortedKeys.map((key) => `"${key}":${this._stableStringify(obj[key])}`);
180
+ return "{" + pairs.join(",") + "}";
181
+ }
182
+ return JSON.stringify(obj);
183
+ }
184
+ /**
185
+ * 取消指定请求
186
+ * @param {RequestKey} key 请求标识
187
+ * @param {string} [reason] 取消原因
188
+ * @returns {boolean} 是否成功取消
189
+ */
190
+ cancelRequest(key, reason) {
191
+ const controller = this._abortControllers.get(key);
192
+ if (controller) {
193
+ controller.abort(reason || "\u8BF7\u6C42\u5DF2\u53D6\u6D88");
194
+ this._abortControllers.delete(key);
195
+ return true;
196
+ }
197
+ return false;
198
+ }
199
+ /**
200
+ * 取消所有请求
201
+ * @param {string} [reason] 取消原因
202
+ * @returns {number} 被取消的请求数量
203
+ */
204
+ cancelAllRequests(reason) {
205
+ const count = this._abortControllers.size;
206
+ this._abortControllers.forEach((controller) => {
207
+ controller.abort(reason || "\u8BF7\u6C42\u5DF2\u53D6\u6D88");
208
+ });
209
+ this._abortControllers.clear();
210
+ return count;
211
+ }
212
+ /**
213
+ * 设置默认请求头
214
+ * @param {string} key 请求头名称
215
+ * @param {string} value 请求头值
216
+ */
217
+ setHeader(key, value) {
218
+ this._instance.defaults.headers.common[key] = value;
219
+ }
220
+ /**
221
+ * 批量设置请求头
222
+ * @param {Record<string, string>} headers 请求头对象
223
+ */
224
+ setHeaders(headers) {
225
+ Object.entries(headers).forEach(([key, value]) => {
226
+ this._instance.defaults.headers.common[key] = value;
227
+ });
228
+ }
229
+ /**
230
+ * 移除请求头
231
+ * @param {string} key 请求头名称
232
+ */
233
+ removeHeader(key) {
234
+ delete this._instance.defaults.headers.common[key];
235
+ }
236
+ /** 获取基础URL */
237
+ getBaseURL() {
238
+ return this._instance.defaults.baseURL || "";
239
+ }
240
+ /** 设置基础URL */
241
+ setBaseURL(url) {
242
+ this._instance.defaults.baseURL = url;
243
+ }
244
+ /** 获取 Axios 实例 */
245
+ getInstance() {
246
+ return this._instance;
247
+ }
248
+ /**
249
+ * 通用请求方法
250
+ * @param {string} method 请求方法
251
+ * @param {string} url 请求地址
252
+ * @param {RequestConfig} [config={}] 请求配置
253
+ * @returns {Promise<AxiosResponse>} 响应数据
254
+ */
255
+ async request(method, url, config = {}) {
256
+ const { requestKey, retry, ...restConfig } = config;
257
+ const retryConfig = {
258
+ ...this._retryConfig,
259
+ ...retry || {}
260
+ };
261
+ const requestConfig = { method, url, ...restConfig };
262
+ let lastError = null;
263
+ const configKey = requestKey != null ? requestKey : this._generateRequestKey(requestConfig);
264
+ for (let attempt = 0; attempt <= retryConfig.count; attempt++) {
265
+ try {
266
+ if (attempt > 0) {
267
+ this._abortControllers.delete(configKey);
268
+ }
269
+ const finalConfig = this._setupAbortController(requestConfig, configKey);
270
+ const result = await this._instance.request(finalConfig);
271
+ return result;
272
+ } catch (error) {
273
+ lastError = error;
274
+ this._abortControllers.delete(configKey);
275
+ const isLast = attempt === retryConfig.count;
276
+ const shouldRetry = retryConfig.condition(error);
277
+ const isCancelled = axios2.isCancel(error);
278
+ if (isLast || !shouldRetry || isCancelled) {
279
+ break;
280
+ }
281
+ if (retryConfig.delay > 0) {
282
+ await sleep(retryConfig.delay);
283
+ }
284
+ }
285
+ }
286
+ return Promise.reject(lastError);
287
+ }
288
+ /**
289
+ * GET请求
290
+ * @param {string} url 请求地址
291
+ * @param {RequestConfig} [options] 请求选项
292
+ * @returns {Promise<AxiosResponse>} 响应数据
293
+ */
294
+ get(url, options = {}) {
295
+ return this.request("GET", url, options);
296
+ }
297
+ /**
298
+ * POST请求
299
+ * @param {string} url 请求地址
300
+ * @param {any} [data] 请求数据
301
+ * @param {RequestConfig} [options] 其他选项
302
+ * @returns {Promise<AxiosResponse>} 响应数据
303
+ */
304
+ post(url, data = {}, options = {}) {
305
+ return this.request("POST", url, { ...options, data });
306
+ }
307
+ /**
308
+ * PUT请求
309
+ * @param {string} url 请求地址
310
+ * @param {any} [data] 请求数据
311
+ * @param {RequestConfig} [options] 其他选项
312
+ * @returns {Promise<AxiosResponse>} 响应数据
313
+ */
314
+ put(url, data = {}, options = {}) {
315
+ return this.request("PUT", url, { ...options, data });
316
+ }
317
+ /**
318
+ * DELETE请求
319
+ * @param {string} url 请求地址
320
+ * @param {RequestConfig} [options] 请求选项
321
+ * @returns {Promise<AxiosResponse>} 响应数据
322
+ */
323
+ delete(url, options = {}) {
324
+ return this.request("DELETE", url, options);
325
+ }
326
+ /**
327
+ * PATCH请求
328
+ * @param {string} url 请求地址
329
+ * @param {any} [data] 请求数据
330
+ * @param {RequestConfig} [options] 其他选项
331
+ * @returns {Promise<AxiosResponse>} 响应数据
332
+ */
333
+ patch(url, data = {}, options = {}) {
334
+ return this.request("PATCH", url, { ...options, data });
335
+ }
336
+ };
337
+ export {
338
+ AxiosWrapperPro
339
+ };
package/dist/utils.d.ts CHANGED
@@ -16,5 +16,5 @@ export declare function sleep(ms: number): Promise<void>;
16
16
  * @param {AxiosError} error 错误对象
17
17
  * @returns {boolean} 如果是axios取消请求的错误则返回true,否则返回false
18
18
  */
19
- export declare function isCancel(error: AxiosError<any>): error is import("axios").CanceledError<any>;
19
+ export declare function isCancel(error: AxiosError<any>): boolean;
20
20
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,QAAQ,CAElE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,+CAE9C"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,QAAQ,CAElE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,WAE9C"}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "axios-wrapper-pro",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "基于 Axios 的增强型 HTTP 客户端,支持请求去重、自动取消、重试机制和可配置拦截器",
5
5
  "scripts": {
6
- "build": "tsc",
7
- "build:watch": "tsc --watch",
6
+ "build": "tsup src/index.ts --format cjs,esm --dts",
7
+ "build:watch": "tsup src/index.ts --format cjs,esm --dts --watch",
8
8
  "release": "npm publish",
9
9
  "test": "npm test"
10
10
  },
@@ -36,9 +36,10 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^22.0.0",
39
- "typescript": "^5.0.0",
40
39
  "axios": "^1.6.0",
41
40
  "ts-loader": "^9.5.0",
41
+ "tsup": "^8.5.1",
42
+ "typescript": "^5.0.0",
42
43
  "webpack": "^5.90.0",
43
44
  "webpack-cli": "^5.1.0"
44
45
  }