enhance-axios 1.0.4 → 1.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/dist/cjs/index.js CHANGED
@@ -39,7 +39,7 @@ __export(index_exports, {
39
39
  module.exports = __toCommonJS(index_exports);
40
40
 
41
41
  // package.json
42
- var version = "1.0.4";
42
+ var version = "1.1.0";
43
43
 
44
44
  // src/core/index.ts
45
45
  var import_axios = __toESM(require("axios"));
@@ -271,52 +271,89 @@ var CONTENT_TYPE_MAP = {
271
271
  form: "application/x-www-form-urlencoded"
272
272
  };
273
273
 
274
- // src/core/index.ts
275
- var DEFAULT_PREVENT_CONFIG = {
276
- enabled: true,
277
- methods: ["POST", "PUT", "PATCH", "DELETE"],
278
- intervalMs: 1e3
279
- };
280
- var DEFAULT_CANCEL_CONFIG = {
281
- enabled: true,
282
- methods: ["GET"]
283
- };
284
- function defaultRetryCondition(error) {
285
- if (!error.response) {
286
- return true;
274
+ // src/core/tokenManager.ts
275
+ function formatHeader(token, fmt) {
276
+ if (typeof fmt === "function") return fmt(token).trim();
277
+ if (typeof fmt === "string") {
278
+ const tpl = fmt.includes("{token}") ? fmt : `${fmt} {token}`;
279
+ return tpl.replace("{token}", token).trim();
280
+ }
281
+ return `Bearer ${token}`;
282
+ }
283
+ function setHeader(config, token, auth) {
284
+ config.headers = config.headers || {};
285
+ config.headers[auth.headerName || "Authorization"] = formatHeader(token, auth.headerFormat);
286
+ }
287
+ function shouldUseToken(config, instanceNeedToken) {
288
+ if (config.needToken !== void 0) return config.needToken;
289
+ if (typeof instanceNeedToken === "function") return instanceNeedToken(config);
290
+ if (instanceNeedToken !== void 0) return instanceNeedToken;
291
+ return true;
292
+ }
293
+ function defaultShouldRefresh(err) {
294
+ return err?.response?.status === 401 || err?.response?.data?.code === 401;
295
+ }
296
+ var TokenManager = class {
297
+ constructor(auth, needTokenDefault) {
298
+ this.auth = auth;
299
+ this.needTokenDefault = needTokenDefault;
300
+ this.pendingRefresh = null;
301
+ }
302
+ /** 请求拦截器:注入 token header */
303
+ async handleRequest(config) {
304
+ if (!shouldUseToken(config, this.needTokenDefault)) return;
305
+ if (this.pendingRefresh) {
306
+ try {
307
+ const info = await this.pendingRefresh;
308
+ setHeader(config, info.accessToken, this.auth);
309
+ return;
310
+ } catch {
311
+ this.pendingRefresh = null;
312
+ }
313
+ }
314
+ try {
315
+ const local = await Promise.resolve(this.auth.getLocalToken());
316
+ if (local) {
317
+ setHeader(config, local.accessToken, this.auth);
318
+ }
319
+ } catch {
320
+ }
287
321
  }
288
- const status = error.response.status;
289
- if (status === 408 || status === 429) {
322
+ /**
323
+ * 响应拦截器(resolve / reject):
324
+ * 检测到 token 过期则刷新并注入新 token。
325
+ * 返回 true 表示调用方需要调用 instance.request(config) 重试。
326
+ * 抛出异常表示刷新失败,调用方应 reject。
327
+ */
328
+ async handleAuthError(responseOrError, config) {
329
+ if (!shouldUseToken(config, this.needTokenDefault)) return false;
330
+ const check = this.auth.shouldRefreshToken || defaultShouldRefresh;
331
+ if (!check(responseOrError)) return false;
332
+ if (!this.pendingRefresh) {
333
+ this.pendingRefresh = this.auth.refreshToken().then(async (info2) => {
334
+ if (this.auth.setLocalToken) {
335
+ await Promise.resolve(this.auth.setLocalToken(info2)).catch(() => {
336
+ });
337
+ }
338
+ return info2;
339
+ });
340
+ }
341
+ const info = await this.pendingRefresh;
342
+ this.pendingRefresh = null;
343
+ setHeader(config, info.accessToken, this.auth);
290
344
  return true;
291
345
  }
292
- if (status >= 500 && status < 600) {
293
- return true;
346
+ /** 刷新失败时调用 */
347
+ handleRefreshFailure(err) {
348
+ this.pendingRefresh = null;
349
+ const handler = this.auth.tokenFailureHandler;
350
+ if (handler) {
351
+ handler("refresh", err);
352
+ }
294
353
  }
295
- return false;
296
- }
297
- var DEFAULT_RETRY_CONFIG = {
298
- enabled: true,
299
- retries: 3,
300
- retryDelay: 1e3,
301
- retryCondition: defaultRetryCondition,
302
- exponential: true,
303
- maxDelay: 3e4
304
354
  };
305
- function shouldApply(method, methods) {
306
- if (methods == null) return true;
307
- if (methods.length === 0) return false;
308
- return methods.includes(method?.toUpperCase() || "GET");
309
- }
310
- function calculateRetryDelay(retryConfig, retryCount) {
311
- let delay = retryConfig.retryDelay;
312
- if (retryConfig.exponential) {
313
- delay = Math.min(
314
- retryConfig.retryDelay * Math.pow(2, retryCount),
315
- retryConfig.maxDelay
316
- );
317
- }
318
- return delay;
319
- }
355
+
356
+ // src/core/dataTransform.ts
320
357
  function getDataFormat(config) {
321
358
  const headers = config.headers || {};
322
359
  const ctKey = Object.keys(headers).find((k) => k.toLowerCase() === "content-type");
@@ -346,9 +383,74 @@ function injectDataTransform(config, format, instance) {
346
383
  }
347
384
  config.transformRequest = [ourTransform, ...chain];
348
385
  }
386
+
387
+ // src/core/helpers.ts
388
+ function shouldApply(method, methods) {
389
+ if (methods == null) return true;
390
+ if (methods.length === 0) return false;
391
+ return methods.includes(method?.toUpperCase() || "GET");
392
+ }
349
393
  function isConfigSet(config) {
350
394
  return config != null;
351
395
  }
396
+
397
+ // src/core/retry.ts
398
+ function defaultRetryCondition(error) {
399
+ if (!error.response) return true;
400
+ const status = error.response.status;
401
+ if (status === 408 || status === 429) return true;
402
+ if (status >= 500 && status < 600) return true;
403
+ return false;
404
+ }
405
+ var DEFAULT_RETRY_CONFIG = {
406
+ enabled: true,
407
+ retries: 3,
408
+ retryDelay: 1e3,
409
+ retryCondition: defaultRetryCondition,
410
+ exponential: true,
411
+ maxDelay: 3e4
412
+ };
413
+ function calculateRetryDelay(config, retryCount) {
414
+ if (!config.exponential) return config.retryDelay;
415
+ return Math.min(config.retryDelay * Math.pow(2, retryCount), config.maxDelay);
416
+ }
417
+ function normalizeRetryConfig(config, defaults) {
418
+ if (!isConfigSet(config)) return defaults;
419
+ if (typeof config === "boolean") return { ...defaults, enabled: config };
420
+ if (typeof config === "number") return { ...defaults, enabled: true, retries: config };
421
+ if (typeof config === "function") return { ...defaults, enabled: true, retryCondition: config };
422
+ if (Array.isArray(config)) {
423
+ const codes = config;
424
+ return {
425
+ ...defaults,
426
+ enabled: true,
427
+ retryCondition: (error) => {
428
+ if (!error.response) return true;
429
+ return codes.includes(error.response.status);
430
+ }
431
+ };
432
+ }
433
+ return {
434
+ enabled: config.enabled ?? true,
435
+ retries: config.retries ?? defaults.retries,
436
+ retryDelay: config.retryDelay ?? defaults.retryDelay,
437
+ retryCondition: config.retryCondition ?? defaults.retryCondition,
438
+ exponential: config.exponential ?? defaults.exponential,
439
+ maxDelay: config.maxDelay ?? defaults.maxDelay,
440
+ methods: config.methods != null ? config.methods : defaults.methods
441
+ };
442
+ }
443
+
444
+ // src/core/index.ts
445
+ var DEFAULT_PREVENT_CONFIG = {
446
+ enabled: true,
447
+ methods: ["POST", "PUT", "PATCH", "DELETE"],
448
+ intervalMs: 1e3
449
+ };
450
+ var DEFAULT_CANCEL_CONFIG = {
451
+ enabled: true,
452
+ methods: ["GET"]
453
+ };
352
454
  function normalizePreventConfig(config, defaults) {
353
455
  if (!isConfigSet(config)) {
354
456
  return defaults;
@@ -397,40 +499,6 @@ function normalizeCancelConfig(config, defaults) {
397
499
  methods: config.methods != null ? config.methods : defaults.methods
398
500
  };
399
501
  }
400
- function normalizeRetryConfig(config, defaults) {
401
- if (!isConfigSet(config)) {
402
- return defaults;
403
- }
404
- if (typeof config === "boolean") {
405
- return { ...defaults, enabled: config };
406
- }
407
- if (typeof config === "number") {
408
- return { ...defaults, enabled: true, retries: config };
409
- }
410
- if (typeof config === "function") {
411
- return { ...defaults, enabled: true, retryCondition: config };
412
- }
413
- if (Array.isArray(config)) {
414
- const codes = config;
415
- return {
416
- ...defaults,
417
- enabled: true,
418
- retryCondition: (error) => {
419
- if (!error.response) return true;
420
- return codes.includes(error.response.status);
421
- }
422
- };
423
- }
424
- return {
425
- enabled: config.enabled ?? true,
426
- retries: config.retries ?? defaults.retries,
427
- retryDelay: config.retryDelay ?? defaults.retryDelay,
428
- retryCondition: config.retryCondition ?? defaults.retryCondition,
429
- exponential: config.exponential ?? defaults.exponential,
430
- maxDelay: config.maxDelay ?? defaults.maxDelay,
431
- methods: config.methods != null ? config.methods : defaults.methods
432
- };
433
- }
434
502
  function getEffectiveConfig(config, instanceDefaults) {
435
503
  const prevent = isConfigSet(config.preventDuplicate) ? normalizePreventConfig(config.preventDuplicate, instanceDefaults.prevent) : { ...instanceDefaults.prevent };
436
504
  const cancel = isConfigSet(config.cancelRequest) ? normalizeCancelConfig(config.cancelRequest, instanceDefaults.cancel) : { ...instanceDefaults.cancel };
@@ -475,7 +543,8 @@ function resolveAndCleanup(config, rm, pr, data) {
475
543
  if (ck && ck !== pk) rm.unregisterRequest(ck, "cancel");
476
544
  }
477
545
  function createEnhanceInstance(options = {}) {
478
- const instance = import_axios.default.create(options);
546
+ const { tokenAuth: _ta, needToken: _nt, ...axiosOptions } = options;
547
+ const instance = import_axios.default.create(axiosOptions);
479
548
  const defaultPrevent = { ...DEFAULT_PREVENT_CONFIG };
480
549
  const defaultCancel = { ...DEFAULT_CANCEL_CONFIG };
481
550
  const defaultRetry = { ...DEFAULT_RETRY_CONFIG };
@@ -492,6 +561,7 @@ function createEnhanceInstance(options = {}) {
492
561
  Object.assign(defaultRetry, normalized);
493
562
  }
494
563
  const needCacheBust = options.needCacheBust ?? true;
564
+ const tokenManager = _ta ? new TokenManager(_ta, _nt) : null;
495
565
  const requestManager = new RequestManager();
496
566
  const pendingReturns = /* @__PURE__ */ new Map();
497
567
  const enhanceInstance = {
@@ -510,9 +580,10 @@ function createEnhanceInstance(options = {}) {
510
580
  getRequestStatus: (key) => requestManager.getRequestStatus(key)
511
581
  };
512
582
  instance.interceptors.request.use(
513
- (config) => {
583
+ async (config) => {
514
584
  const method = config.method?.toUpperCase() || "GET";
515
585
  const { prevent, cancel } = getEffectiveConfig(config, { prevent: defaultPrevent, cancel: defaultCancel });
586
+ if (tokenManager) await tokenManager.handleRequest(config);
516
587
  const headers = config.headers || {};
517
588
  const hasContentType = typeof headers === "object" && Object.keys(headers).some((k) => k.toLowerCase() === "content-type");
518
589
  if (!hasContentType) {
@@ -609,6 +680,18 @@ function createEnhanceInstance(options = {}) {
609
680
  // ─────────────────────────────────────────────────────────────────────────
610
681
  async (response) => {
611
682
  const config = response.config;
683
+ if (tokenManager) {
684
+ try {
685
+ if (await tokenManager.handleAuthError(response, config)) {
686
+ cleanupRegistered(config, requestManager);
687
+ return instance.request(config);
688
+ }
689
+ } catch (err) {
690
+ tokenManager.handleRefreshFailure(err);
691
+ rejectAndCleanup(config, requestManager, pendingReturns, err);
692
+ return Promise.reject(err);
693
+ }
694
+ }
612
695
  const retryConfig = normalizeRetryConfig(config.retry, defaultRetry);
613
696
  if (retryConfig.enabled && shouldApply(config.method, retryConfig.methods)) {
614
697
  const syntheticError = new Error("Business logic error");
@@ -641,6 +724,18 @@ function createEnhanceInstance(options = {}) {
641
724
  rejectAndCleanup(config, requestManager, pendingReturns, error);
642
725
  return Promise.reject(error);
643
726
  }
727
+ if (tokenManager) {
728
+ try {
729
+ if (await tokenManager.handleAuthError(error, config)) {
730
+ cleanupRegistered(config, requestManager);
731
+ return instance.request(config);
732
+ }
733
+ } catch (err) {
734
+ tokenManager.handleRefreshFailure(err);
735
+ rejectAndCleanup(config, requestManager, pendingReturns, err);
736
+ return Promise.reject(err);
737
+ }
738
+ }
644
739
  const retryConfig = normalizeRetryConfig(config.retry, defaultRetry);
645
740
  if (retryConfig.enabled && shouldApply(config.method, retryConfig.methods)) {
646
741
  const retryCount = config.__retryCount || 0;