enhance-axios 1.0.2
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 +395 -0
- package/dist/cjs/index.js +686 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/index.min.js +1 -0
- package/dist/esm/index.d.mts +363 -0
- package/dist/esm/index.min.mjs +1 -0
- package/dist/esm/index.mjs +645 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/umd/index.global.js +670 -0
- package/dist/umd/index.global.js.map +1 -0
- package/dist/umd/index.min.global.js +1 -0
- package/dist/umd.bundle/index.axios.global.js +3751 -0
- package/dist/umd.bundle/index.axios.global.js.map +1 -0
- package/dist/umd.bundle/index.axios.min.global.js +9 -0
- package/package.json +95 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/index.ts","../../src/core/requestManager.ts","../../src/utils/common.ts","../../src/utils/keyGenerator.ts","../../src/utils/formData.ts","../../src/types/index.ts","../../src/version.ts"],"sourcesContent":["/**\n * enhance-axios 核心模块\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * 功能说明\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * 五个增强能力:\n * 1. 防重复提交 (preventDuplicate) — 短时间内相同请求复用第一次的结果\n * 2. 取消请求 (cancelRequest) — 新请求到达时取消旧请求,始终保留最新\n * 3. 失败重试 (retry) — HTTP 错误或业务码异常时自动重试\n * 4. 数据转换 (contentType) — 根据 Content-Type 自动转换 data 格式\n * 5. 缓存破坏 (needCacheBust) — 所有请求追加 _ 参数防止缓存\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * 默认策略\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * 功能 | 默认启用 | 默认 methods | 默认 key 生成\n * --------|---------|----------------------------------|------------------\n * 防重复 | 是 | POST, PUT, PATCH, DELETE | hash(method|url|params|data)\n * 取消请求| 是 | GET | 同上\n * 重试 | 是 | 全部 | N/A\n * 数据转换| 是 | N/A (有 data 的请求) | N/A\n * 缓存破坏| 是 | 全部 | N/A\n *\n * 防重复和取消请求通过 methods 各自控制生效范围,默认互不重叠。\n * 同一请求同时命中两者时:步骤 3(取消旧请求)→ 步骤 4(防重复检查)→ 步骤 5(注册)。\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * 配置规则\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * 1. 请求级配置覆盖实例级配置\n * 2. 请求级传入 object 默认 enabled: true(显式 opt-in)\n * 3. 快捷写法(string/function/number/array)暗含 enabled: true\n * 4. needCacheBust 仅 false 关闭,其他值一律视为 true\n * 5. methods: undefined / null → 全部方法,methods: [] → 不应用\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * 请求拦截器流程\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * 步骤 1 — 获取有效配置 请求级 > 实例级\n * 步骤 2 — Content-Type 处理 默认 json,file 不设(浏览器自动 boundary)\n * 步骤 3 — 取消旧请求 同 cancelKey 的旧请求被 abort\n * 步骤 4 — 防重复检查 同 preventKey 且在 intervalMs 内 → 阻止,返回 deferred.promise\n * 步骤 5 — 注册新请求 AbortController + requestManager 双 Map 注册\n * 步骤 6 — 数据转换注入 file/form → transformRequest(json 由 axios 处理)\n * 步骤 7 — 缓存破坏 追加 _=<timestamp> 到 params(key 生成后,不影响防重复)\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * 响应拦截器流程\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * 成功 (2xx):\n * 1. 业务码重试检测(retryCondition 在 success handler 中直接判断)\n * 2. resolve deferred → 清理 pendingReturns + requestManager\n *\n * 错误 (非 2xx / 网络错误 / 取消):\n * 情况 1 ─ 防重复拦截 → 返回 deferred.promise(不清理,等待者拿原请求结果)\n * 情况 2 ─ 请求被取消 → reject deferred → 清理 → 抛出\n * 情况 3 ─ 满足重试条件 → 保留 deferred → 清理 requestManager → 延迟后重试\n * 情况 4 ─ 不满足/重试耗尽 → reject deferred → 清理 → 抛出\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * deferred 机制\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * pendingReturns: Map<key, { resolve, reject, promise }>\n * 请求 A 创建 deferred — 请求 B 被拦截时拿到 A 的 deferred.promise\n * 重试链复用同一个 deferred — 被拦截的请求拿到最终结果而非中间失败\n *\n * requestManager: { preventPending, cancelPending }\n * 两个独立 Map,各自存 { key, config, controller, promise, timestamp }\n * controller 用于 abort(),promise 指向 pendingReturns 的 deferred.promise\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * 清理时机\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * 操作 | pendingReturns | requestManager | deferred\n * ------------------|----------------|----------------|----------\n * 成功 / 重试成功 | 删除 | 取消注册 | resolve\n * 失败 / 重试耗尽 | 删除 | 取消注册 | reject\n * 重试前 | 保留 | 取消注册 | 保留\n * 防重复拦截 | - | - | -\n * 请求被取消 | 删除 | 取消注册 | reject\n * clearAll() | 全部删除 | 全部清空 | reject 全部\n *\n * ════════════════════════════════════════════════════════════════════════════════\n * 重试场景\n * ════════════════════════════════════════════════════════════════════════════════\n *\n * 场景 | HTTP | 重试 | 判断方式\n * -------------------|--------|------|------------------\n * 网络错误 | 无 | 是 | !error.response\n * 408 / 429 / 5xx | >=400 | 是 | retryCondition\n * 4xx 客户端错误 | 400+ | 否 | 默认不重试\n * 请求取消 | - | 否 | axios.isCancel()\n * 防重复拦截 | - | 否 | __preventReturn\n * 2xx 业务码异常 | 200 | 自定义| success handler 中 retryCondition\n */\n\nimport axios, { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios';\nimport { RequestManager } from './requestManager';\nimport { resolveRequestKey, getFormData } from '../utils';\nimport type {\n CreateEnhanceOptions,\n EnhanceInstance,\n PreventDuplicateConfig,\n CancelRequestConfig,\n RetryConfig,\n PreventDuplicateOption,\n CancelRequestOption,\n RetryOption,\n InternalPreventConfig,\n InternalCancelConfig,\n InternalRetryConfig,\n RequestMethod,\n} from '../types';\nimport { CONTENT_TYPE_MAP } from '../types';\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 存储防重复请求的延迟 Promise\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 延迟 Promise 结构\n *\n * 用于防重复提交:当检测到重复请求时,后续请求可以等待原始请求的结果。\n * Promise 会在原始请求(包括重试)最终完成时被 resolve/reject。\n * 重试链会复用同一个 deferred,保证后续请求拿到最终结果而非中间失败。\n */\ninterface PendingDeferred {\n resolve: (value: unknown) => void;\n reject: (reason: unknown) => void;\n promise: Promise<unknown>;\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 默认配置\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 默认防重复配置\n */\nconst DEFAULT_PREVENT_CONFIG: InternalPreventConfig = {\n enabled: true,\n methods: ['POST', 'PUT', 'PATCH', 'DELETE'],\n intervalMs: 1000,\n};\n\n/**\n * 默认取消请求配置\n */\nconst DEFAULT_CANCEL_CONFIG: InternalCancelConfig = {\n enabled: true,\n methods: ['GET'],\n};\n\n/**\n * 默认重试条件(可导出复用)\n *\n * - 网络错误 / CORS 等(无 response)→ 重试\n * - 408 Request Timeout → 重试\n * - 429 Too Many Requests → 重试\n * - 5xx 服务器错误 → 重试\n * - 其他(4xx 等)→ 不重试\n */\nexport function defaultRetryCondition(error: AxiosError): boolean {\n if (!error.response) {\n return true;\n }\n const status = error.response.status;\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500 && status < 600) {\n return true;\n }\n return false;\n}\n\n/**\n * 默认重试配置\n */\nconst DEFAULT_RETRY_CONFIG: InternalRetryConfig = {\n enabled: true,\n retries: 3,\n retryDelay: 1000,\n retryCondition: defaultRetryCondition,\n exponential: true,\n maxDelay: 30000,\n};\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 工具函数\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 检查 HTTP 方法是否在允许列表中\n */\nfunction shouldApply(method?: string, methods?: string[] | null): boolean {\n if (methods == null) return true;\n if (methods.length === 0) return false;\n return methods.includes(method?.toUpperCase() || 'GET');\n}\n\n/**\n * 计算重试延迟(支持指数退避)\n *\n * @param retryConfig 重试配置\n * @param retryCount 当前重试次数(从 0 开始)\n * @returns 延迟时间(ms)\n *\n * 指数退避公式:min(retryDelay * 2^retryCount, maxDelay)\n */\nfunction calculateRetryDelay(\n retryConfig: { retryDelay: number; exponential: boolean; maxDelay: number },\n retryCount: number\n): number {\n let delay = retryConfig.retryDelay;\n if (retryConfig.exponential) {\n delay = Math.min(\n retryConfig.retryDelay * Math.pow(2, retryCount),\n retryConfig.maxDelay\n );\n }\n return delay;\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 数据自动转换(transformRequest 注入)\n// ════════════════════════════════════════════════════════════════════════════════\n\nfunction getDataFormat(config: AxiosRequestConfig): string | undefined {\n const headers = config.headers || {};\n const ctKey = Object.keys(headers).find(k => k.toLowerCase() === 'content-type');\n if (ctKey) {\n const ct = String(headers[ctKey]).toLowerCase();\n if (ct.includes('multipart/form-data')) return 'file';\n if (ct.includes('application/x-www-form-urlencoded')) return 'form';\n if (ct.includes('application/json') || ct.includes('+json')) return 'json';\n }\n return config.contentType;\n}\n\nfunction injectDataTransform(\n config: AxiosRequestConfig,\n format: 'file' | 'form',\n instance: AxiosInstance,\n): void {\n if ((config as any).__dataTransformInjected) return;\n (config as any).__dataTransformInjected = true;\n\n const ourTransform = (data: unknown) => {\n if (data == null || data instanceof FormData || data instanceof URLSearchParams) return data;\n if (typeof data !== 'object') return data;\n if (format === 'file') return getFormData(data);\n return new URLSearchParams(data as Record<string, string>);\n };\n\n const existing = config.transformRequest;\n const defaults = instance.defaults.transformRequest;\n const source = existing != null ? existing : defaults;\n let chain: ((...args: any[]) => any)[] = [];\n if (source != null) {\n chain = Array.isArray(source) ? [...source] : [source];\n }\n config.transformRequest = [ourTransform, ...chain];\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 配置归一化函数\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 判断配置是否已设置(不是 undefined/null)\n */\nfunction isConfigSet(config: any): boolean {\n return config != null;\n}\n\n/**\n * 配置归一化:防重复提交\n *\n * 支持的输入格式:\n * - boolean: 赋给 enabled\n * - string: 赋给 requestKey\n * - function: 赋给 requestKey\n * - number: 赋给 intervalMs\n * - array: 赋给 methods\n * - object: 合并到配置\n * - undefined/null: 视为未传递,使用默认值\n */\nfunction normalizePreventConfig(\n config: PreventDuplicateOption | undefined,\n defaults: InternalPreventConfig\n): InternalPreventConfig {\n // undefined/null 视为未传递\n if (!isConfigSet(config)) {\n return defaults;\n }\n\n // boolean -> enabled\n if (typeof config === 'boolean') {\n return { ...defaults, enabled: config };\n }\n\n // string -> requestKey\n if (typeof config === 'string') {\n return { ...defaults, enabled: true, requestKey: config };\n }\n\n // function -> requestKey\n if (typeof config === 'function') {\n return { ...defaults, enabled: true, requestKey: config as (cfg: AxiosRequestConfig, h: (s: string) => string) => string };\n }\n\n // number -> intervalMs\n if (typeof config === 'number') {\n return { ...defaults, enabled: true, intervalMs: config };\n }\n\n // array -> methods\n if (Array.isArray(config)) {\n return { ...defaults, enabled: true, methods: [...(config as string[])] };\n }\n\n // object -> 合并\n return {\n enabled: (config as PreventDuplicateConfig).enabled ?? true,\n requestKey: (config as PreventDuplicateConfig).requestKey ?? defaults.requestKey,\n methods: (config as PreventDuplicateConfig).methods != null\n ? (config as PreventDuplicateConfig).methods\n : defaults.methods,\n intervalMs: (config as PreventDuplicateConfig).intervalMs ?? defaults.intervalMs,\n };\n}\n\n/**\n * 配置归一化:取消请求\n *\n * 支持的输入格式同 normalizePreventConfig\n */\nfunction normalizeCancelConfig(\n config: CancelRequestOption | undefined,\n defaults: InternalCancelConfig\n): InternalCancelConfig {\n if (!isConfigSet(config)) {\n return defaults;\n }\n\n if (typeof config === 'boolean') {\n return { ...defaults, enabled: config };\n }\n\n if (typeof config === 'string') {\n return { ...defaults, enabled: true, requestKey: config };\n }\n\n if (typeof config === 'function') {\n return { ...defaults, enabled: true, requestKey: config as (cfg: AxiosRequestConfig, h: (s: string) => string) => string };\n }\n\n if (Array.isArray(config)) {\n return { ...defaults, enabled: true, methods: [...(config as string[])] };\n }\n\n return {\n enabled: (config as CancelRequestConfig).enabled ?? true,\n requestKey: (config as CancelRequestConfig).requestKey ?? defaults.requestKey,\n methods: (config as CancelRequestConfig).methods != null\n ? (config as CancelRequestConfig).methods\n : defaults.methods,\n };\n}\n\n/**\n * 配置归一化:失败重试\n *\n * 支持的输入格式:\n * - boolean: 赋给 enabled\n * - number: 赋给 retries\n * - number[]: 生成 retryCondition(匹配数组中状态码或网络错误)\n * - function: 赋给 retryCondition\n * - object: 合并到配置\n * - undefined/null: 视为未传递,使用默认值\n *\n * 注意:非对象类型的快捷方式默认开启该功能(enabled: true),\n * 仅 retry: false 时明确关闭。\n */\nfunction normalizeRetryConfig(\n config: RetryOption | undefined,\n defaults: InternalRetryConfig\n): InternalRetryConfig {\n if (!isConfigSet(config)) {\n return defaults;\n }\n\n if (typeof config === 'boolean') {\n return { ...defaults, enabled: config };\n }\n\n if (typeof config === 'number') {\n return { ...defaults, enabled: true, retries: config };\n }\n\n if (typeof config === 'function') {\n return { ...defaults, enabled: true, retryCondition: config as (error: AxiosError) => boolean };\n }\n\n if (Array.isArray(config)) {\n const codes = config as number[];\n return {\n ...defaults,\n enabled: true,\n retryCondition: (error: AxiosError) => {\n if (!error.response) return true;\n return codes.includes(error.response.status);\n },\n };\n }\n\n return {\n enabled: (config as RetryConfig).enabled ?? true,\n retries: (config as RetryConfig).retries ?? defaults.retries,\n retryDelay: (config as RetryConfig).retryDelay ?? defaults.retryDelay,\n retryCondition: (config as RetryConfig).retryCondition ?? defaults.retryCondition,\n exponential: (config as RetryConfig).exponential ?? defaults.exponential,\n maxDelay: (config as RetryConfig).maxDelay ?? defaults.maxDelay,\n methods: (config as RetryConfig).methods != null\n ? (config as RetryConfig).methods\n : defaults.methods,\n };\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 核心函数\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 获取有效的增强配置\n *\n * 优先级规则:\n * 1. 请求级配置优先于实例级配置(通过 methods 数组控制生效方法)\n * 2. 未设置时使用实例默认配置\n * 3. 默认 methods:防重复 -> POST/PUT/PATCH/DELETE,取消请求 -> GET\n *\n * @param config 请求配置\n * @param instanceDefaults 实例默认配置\n */\nfunction getEffectiveConfig(\n config: AxiosRequestConfig,\n instanceDefaults: {\n prevent: InternalPreventConfig;\n cancel: InternalCancelConfig;\n }\n): { prevent: InternalPreventConfig; cancel: InternalCancelConfig } {\n const prevent = isConfigSet(config.preventDuplicate)\n ? normalizePreventConfig(config.preventDuplicate, instanceDefaults.prevent)\n : { ...instanceDefaults.prevent };\n\n const cancel = isConfigSet(config.cancelRequest)\n ? normalizeCancelConfig(config.cancelRequest, instanceDefaults.cancel)\n : { ...instanceDefaults.cancel };\n\n return { prevent, cancel };\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 请求清理辅助\n// ════════════════════════════════════════════════════════════════════════════════\n\nfunction getPendingKey(config: AxiosRequestConfig): string | undefined {\n return (config as any).__pendingKey;\n}\nfunction getCancelKey(config: AxiosRequestConfig): string | undefined {\n return (config as any).__cancelKey;\n}\n\n/**\n * 清理 requestManager 中的注册记录(不操作 deferred)\n */\nfunction cleanupRegistered(config: AxiosRequestConfig, rm: RequestManager): void {\n const pk = getPendingKey(config);\n const ck = getCancelKey(config);\n if (pk) rm.unregisterRequest(pk, 'prevent');\n if (ck && ck !== pk) rm.unregisterRequest(ck, 'cancel');\n}\n\n/**\n * 失败时:reject deferred + 清理\n */\nfunction rejectAndCleanup(\n config: AxiosRequestConfig, rm: RequestManager,\n pr: Map<string, PendingDeferred>, reason: unknown\n): void {\n const pk = getPendingKey(config);\n const ck = getCancelKey(config);\n if (pk) {\n const df = pr.get(pk);\n if (df) { df.reject(reason); pr.delete(pk); }\n rm.unregisterRequest(pk, 'prevent');\n }\n if (ck && ck !== pk) rm.unregisterRequest(ck, 'cancel');\n}\n\nfunction resolveAndCleanup(\n config: AxiosRequestConfig, rm: RequestManager,\n pr: Map<string, PendingDeferred>, data: unknown\n): void {\n const pk = getPendingKey(config);\n const ck = getCancelKey(config);\n if (pk) {\n const df = pr.get(pk);\n if (df) { df.resolve(data); pr.delete(pk); }\n rm.unregisterRequest(pk, 'prevent');\n }\n if (ck && ck !== pk) rm.unregisterRequest(ck, 'cancel');\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 主函数\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 创建增强的 axios 实例\n *\n * @param options 实例配置\n * @returns 增强后的 axios 实例\n */\nfunction createEnhanceInstance(options: CreateEnhanceOptions = {}): AxiosInstance & { enhance: EnhanceInstance } {\n // ─────────────────────────────────────────────────────────────────────────\n // 创建原生 axios 实例\n // ─────────────────────────────────────────────────────────────────────────\n const instance = axios.create(options);\n\n // ─────────────────────────────────────────────────────────────────────────\n // 初始化默认配置\n // ─────────────────────────────────────────────────────────────────────────\n const defaultPrevent = { ...DEFAULT_PREVENT_CONFIG };\n const defaultCancel = { ...DEFAULT_CANCEL_CONFIG };\n const defaultRetry = { ...DEFAULT_RETRY_CONFIG };\n\n // 处理实例级别的配置归一化\n if (isConfigSet(options.preventDuplicate)) {\n const normalized = normalizePreventConfig(options.preventDuplicate, DEFAULT_PREVENT_CONFIG);\n Object.assign(defaultPrevent, normalized);\n }\n\n if (isConfigSet(options.cancelRequest)) {\n const normalized = normalizeCancelConfig(options.cancelRequest, DEFAULT_CANCEL_CONFIG);\n Object.assign(defaultCancel, normalized);\n }\n\n if (isConfigSet(options.retry)) {\n const normalized = normalizeRetryConfig(options.retry, DEFAULT_RETRY_CONFIG);\n Object.assign(defaultRetry, normalized);\n }\n\n const needCacheBust = options.needCacheBust ?? true;\n\n // ─────────────────────────────────────────────────────────────────────────\n // 初始化请求管理器 和 延迟 Promise 存储\n // ─────────────────────────────────────────────────────────────────────────\n const requestManager = new RequestManager();\n const pendingReturns = new Map<string, PendingDeferred>();\n\n // ─────────────────────────────────────────────────────────────────────────\n // 暴露给用户的 enhance API\n // ─────────────────────────────────────────────────────────────────────────\n const enhanceInstance: EnhanceInstance = {\n requestManager,\n clearAll: () => {\n for (const [_key, deferred] of pendingReturns) {\n try { deferred.reject(new Error('All requests cleared')); } catch { }\n }\n pendingReturns.clear();\n requestManager.clearAll();\n },\n cancelRequest: (key: string) => requestManager.cancelRequest(key),\n getRequestStatus: (key: string) => requestManager.getRequestStatus(key),\n };\n\n // ════════════════════════════════════════════════════════════════════════════\n // 请求拦截器\n // ════════════════════════════════════════════════════════════════════════════\n instance.interceptors.request.use(\n (config) => {\n const method = config.method?.toUpperCase() || 'GET';\n\n // ─────────────────────────────────────────────────────────────────────\n // 步骤 1:获取有效的增强配置\n // ─────────────────────────────────────────────────────────────────────\n const { prevent, cancel } = getEffectiveConfig(config, { prevent: defaultPrevent, cancel: defaultCancel });\n\n // ─────────────────────────────────────────────────────────────────────\n // 步骤 2:处理 Content-Type\n // ─────────────────────────────────────────────────────────────────────\n // 仅在未显式设置 Content-Type 时处理(大小写不敏感)\n // 'json' → application/json;charset=UTF-8(默认)\n // 'form' → application/x-www-form-urlencoded\n // 'file' → 不设置(multipart/form-data 需要 boundary)\n // 自定义字符串 → 直接使用\n const headers = config.headers || {};\n const hasContentType = typeof headers === 'object'\n && Object.keys(headers).some(k => k.toLowerCase() === 'content-type');\n\n if (!hasContentType) {\n const contentType = config.contentType;\n\n if (contentType !== 'file') {\n config.headers = config.headers || {};\n const value = contentType != null\n ? (CONTENT_TYPE_MAP[contentType] || contentType)\n : CONTENT_TYPE_MAP.json;\n config.headers['Content-Type'] = value;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // 步骤 3:取消旧请求(同 key 的旧请求被中止)\n // ─────────────────────────────────────────────────────────────────────\n if (cancel.enabled && shouldApply(method, cancel.methods)) {\n const key = resolveRequestKey(config, cancel.requestKey);\n // 清除旧请求的 key 标记,避免其异步 error handler 误删新请求的注册\n const existing = requestManager.getRequestStatus(key);\n if (existing?.config) {\n (existing.config as any).__cancelKey = undefined;\n (existing.config as any).__pendingKey = undefined;\n }\n requestManager.cancelRequest(key);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // 步骤 4:防重复检查(同 key 且在 intervalMs 内则阻止当前请求)\n // ─────────────────────────────────────────────────────────────────────\n if (prevent.enabled && shouldApply(method, prevent.methods)) {\n const key = resolveRequestKey(config, prevent.requestKey);\n\n // 检查是否有正在进行的相同请求\n const existing = requestManager.getRequestStatus(key);\n if (existing) {\n const now = Date.now();\n // 如果请求还在 intervalMs 内,则返回已有请求的 Promise\n if (now - existing.timestamp < prevent.intervalMs) {\n const deferred = pendingReturns.get(key);\n if (deferred) {\n // 阻止当前请求:通过 AbortController 中止本次请求\n const controller = new AbortController();\n config.signal = controller.signal;\n controller.abort('Request prevented by duplicate');\n\n // 保存 key,用于响应拦截器中可能需要的清理\n (config as any).__pendingKey = key;\n\n // 创建错误对象,携带原请求的 Promise 给调用方\n const error = new Error('Request prevented by duplicate') as AxiosError;\n (error as any).__preventReturn = true;\n (error as any).__pendingPromise = deferred.promise;\n (error as any).__pendingKey = key;\n error.config = config;\n\n return Promise.reject(error);\n }\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // 步骤 5:注册新请求(创建 AbortController 供后续 cancel/prevent 使用)\n // ─────────────────────────────────────────────────────────────────────\n const needsPrevent = prevent.enabled && shouldApply(method, prevent.methods);\n const needsCancel = cancel.enabled && shouldApply(method, cancel.methods);\n\n if (needsPrevent || needsCancel) {\n const controller = new AbortController();\n config.signal = controller.signal;\n (config as any).__controller = controller;\n\n if (needsCancel) {\n const cancelKey = resolveRequestKey(config, cancel.requestKey);\n (config as any).__cancelKey = cancelKey;\n requestManager.registerRequest(cancelKey, 'cancel', controller, Promise.resolve(), config);\n }\n\n if (needsPrevent) {\n const preventKey = resolveRequestKey(config, prevent.requestKey);\n (config as any).__pendingKey = preventKey;\n\n let deferred = pendingReturns.get(preventKey);\n if (!deferred) {\n let resolveFn: (value: unknown) => void;\n let rejectFn: (reason: unknown) => void;\n const promise = new Promise<unknown>((resolve, reject) => {\n resolveFn = resolve;\n rejectFn = reject;\n });\n deferred = { resolve: resolveFn!, reject: rejectFn!, promise };\n pendingReturns.set(preventKey, deferred);\n }\n\n requestManager.registerRequest(preventKey, 'prevent', controller, deferred.promise, config);\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // 步骤 6:注入数据转换(file/form → transformRequest,json 由 axios 默认处理)\n // ─────────────────────────────────────────────────────────────────────\n const format = getDataFormat(config);\n if (format === 'file' || format === 'form') {\n injectDataTransform(config, format, instance);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // 步骤 7:缓存破坏(追加 _ 参数,key 生成后执行,stripCacheParam 自动剔除不影响 key)\n // ─────────────────────────────────────────────────────────────────────\n if ((config.needCacheBust ?? needCacheBust) !== false) {\n const stamp = Date.now().toString(36);\n if (config.params instanceof URLSearchParams) {\n config.params.append('_', stamp);\n } else if (typeof config.params === 'object' && config.params !== null) {\n config.params = { ...config.params, _: stamp };\n } else {\n config.params = { _: stamp };\n }\n }\n\n return config;\n },\n (error) => {\n if (error?.config) rejectAndCleanup(error.config, requestManager, pendingReturns, error);\n return Promise.reject(error);\n }\n );\n\n // ════════════════════════════════════════════════════════════════════════════\n // 响应拦截器\n // ════════════════════════════════════════════════════════════════════════════\n instance.interceptors.response.use(\n // ─────────────────────────────────────────────────────────────────────────\n // 成功响应处理 (2xx)\n // ─────────────────────────────────────────────────────────────────────────\n async (response) => {\n const config = response.config;\n\n // ─────────────────────────────────────────────────────────────────────\n // 检查业务码重试(2xx 但业务逻辑失败)\n // ─────────────────────────────────────────────────────────────────────\n const retryConfig = normalizeRetryConfig(config.retry, defaultRetry);\n if (retryConfig.enabled && shouldApply(config.method, retryConfig.methods)) {\n const syntheticError = new Error('Business logic error') as AxiosError;\n syntheticError.config = config;\n syntheticError.response = response;\n syntheticError.isAxiosError = true;\n\n if (retryConfig.retryCondition(syntheticError)) {\n const retryCount = (config as any).__retryCount || 0;\n if (retryCount < retryConfig.retries) {\n await new Promise((resolve) => setTimeout(resolve, calculateRetryDelay(retryConfig, retryCount)));\n cleanupRegistered(config, requestManager);\n (config as any).__retryCount = retryCount + 1;\n return instance.request(config);\n }\n }\n }\n\n resolveAndCleanup(config, requestManager, pendingReturns, response);\n return response;\n },\n\n // ─────────────────────────────────────────────────────────────────────────\n // 错误响应处理 (非 2xx / 网络错误 / 取消 / 防重复拦截)\n // ─────────────────────────────────────────────────────────────────────────\n async (error) => {\n const config = error.config || (error as any).config;\n if (!config) return Promise.reject(error);\n\n // 情况 1:防重复拦截 → 返回原始 deferred.promise\n if ((error as any)?.__preventReturn && (error as any)?.__pendingPromise) {\n return (error as any).__pendingPromise;\n }\n\n // 情况 2:请求被取消 → reject + 清理(不重试)\n if (axios.isCancel(error)) {\n rejectAndCleanup(config, requestManager, pendingReturns, error);\n return Promise.reject(error);\n }\n\n // 情况 3:重试\n const retryConfig = normalizeRetryConfig(config.retry, defaultRetry);\n if (retryConfig.enabled && shouldApply(config.method, retryConfig.methods)) {\n const retryCount = (config as any).__retryCount || 0;\n\n const shouldRetry =\n retryCount < retryConfig.retries &&\n retryConfig.retryCondition(error);\n\n if (shouldRetry) {\n await new Promise((resolve) => setTimeout(resolve, calculateRetryDelay(retryConfig, retryCount)));\n cleanupRegistered(config, requestManager);\n (config as any).__retryCount = retryCount + 1;\n return instance.request(config);\n }\n }\n\n // 情况 4:不需要重试或重试耗尽,清理并抛出错误\n rejectAndCleanup(config, requestManager, pendingReturns, error);\n return Promise.reject(error);\n }\n );\n\n // ════════════════════════════════════════════════════════════════════════════\n // 添加 RESTful 方法封装\n // ════════════════════════════════════════════════════════════════════════════\n const methods: RequestMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];\n\n for (const method of methods) {\n (instance as any)[method.toLowerCase()] = (url: string, data?: any, config?: AxiosRequestConfig) => {\n const finalConfig: AxiosRequestConfig = {\n ...config,\n url,\n method: method,\n };\n\n // 根据方法类型决定 data 参数的位置\n if (['GET', 'HEAD', 'OPTIONS'].includes(method)) {\n if (data) finalConfig.params = data;\n } else {\n if (data !== undefined) finalConfig.data = data;\n }\n\n return instance.request(finalConfig);\n };\n }\n\n // 添加 enhance 属性\n (instance as any).enhance = enhanceInstance;\n\n return instance as AxiosInstance & { enhance: EnhanceInstance };\n}\n\nexport { createEnhanceInstance };\n","/**\n * 请求管理器\n *\n * 负责管理所有 pending 状态的请求,支持:\n * 1. 防重复提交:检查是否有相同的正在进行的请求\n * 2. 取消请求:取消指定的正在进行的请求\n *\n * 存储结构:\n * - preventPending: 防重复提交的 pending 请求(key 来自 preventDuplicate.requestKey)\n * - cancelPending: 取消请求的 pending 请求(key 来自 cancelRequest.requestKey)\n *\n * 两个 Map 独立,同一个 key 可同时存在于两者(各自 requestKey 可能不同)。\n *\n * 取消机制:使用 AbortController / AbortSignal(axios 1.x 推荐)\n */\n\nimport type { AxiosRequestConfig } from 'axios';\nimport type { PendingRequest } from '../types';\n\nexport class RequestManager {\n private preventPending = new Map<string, PendingRequest>();\n private cancelPending = new Map<string, PendingRequest>();\n\n /**\n * 注册一个新请求\n */\n registerRequest(\n key: string,\n type: 'prevent' | 'cancel',\n controller: AbortController,\n promise: Promise<unknown>,\n config?: AxiosRequestConfig,\n ): void {\n const pending: PendingRequest = {\n key,\n config: config || ({} as AxiosRequestConfig),\n controller,\n promise,\n timestamp: Date.now(),\n };\n (type === 'prevent' ? this.preventPending : this.cancelPending).set(key, pending);\n }\n\n /**\n * 移除请求记录\n */\n unregisterRequest(key: string, type: 'prevent' | 'cancel'): void {\n (type === 'prevent' ? this.preventPending : this.cancelPending).delete(key);\n }\n\n /**\n * 取消并移除请求,同时检查两个 Map\n */\n cancelRequest(key: string): boolean {\n let cancelled = false;\n\n const abort = (map: Map<string, PendingRequest>) => {\n const req = map.get(key);\n if (req) {\n try { req.controller.abort('Cancelled by cancelRequest'); } catch { /* noop */ }\n map.delete(key);\n cancelled = true;\n }\n };\n\n abort(this.preventPending);\n abort(this.cancelPending);\n return cancelled;\n }\n\n /**\n * 获取请求状态(优先返回 preventPending)\n */\n getRequestStatus(key: string): PendingRequest | undefined {\n return this.preventPending.get(key) ?? this.cancelPending.get(key);\n }\n\n getPreventPending(key: string): PendingRequest | undefined {\n return this.preventPending.get(key);\n }\n\n getCancelPending(key: string): PendingRequest | undefined {\n return this.cancelPending.get(key);\n }\n\n /**\n * 清空所有 pending 请求\n */\n clearAll(): void {\n const abortAll = (map: Map<string, PendingRequest>, reason: string) => {\n for (const req of map.values()) {\n try { req.controller.abort(reason); } catch { /* noop */ }\n }\n map.clear();\n };\n\n abortAll(this.preventPending, 'Cleared by clearAll');\n abortAll(this.cancelPending, 'Cleared by clearAll');\n }\n\n /**\n * 获取 pending 数量(注意两 Map 独立,合计可能重复计数)\n */\n getPendingCount(): { prevent: number; cancel: number; total: number } {\n return {\n prevent: this.preventPending.size,\n cancel: this.cancelPending.size,\n total: this.preventPending.size + this.cancelPending.size,\n };\n }\n\n /**\n * 获取所有 pending 的 key\n */\n getPendingKeys(): { prevent: string[]; cancel: string[] } {\n return {\n prevent: Array.from(this.preventPending.keys()),\n cancel: Array.from(this.cancelPending.keys()),\n };\n }\n}\n","/**\n * 内部共享工具\n */\n\n/**\n * 检查值是否为可安全遍历键的普通对象\n * 排除 Array / Blob / Date / FormData / Map / Set 等内置类型\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n if (Array.isArray(value)) return false;\n if (value instanceof Blob) return false;\n if (value instanceof Date) return false;\n if (typeof FormData !== 'undefined' && value instanceof FormData) return false;\n if (typeof Map !== 'undefined' && value instanceof Map) return false;\n if (typeof Set !== 'undefined' && value instanceof Set) return false;\n return true;\n}\n","import type { AxiosRequestConfig } from 'axios';\nimport { isPlainObject } from './common';\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 辅助函数\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 将特殊类型转为普通对象,供模板解析和哈希使用:\n * URLSearchParams → { key: value, ... }\n * 其他(Blob/FormData/原值)→ 原样返回\n */\nfunction toPlain(value: unknown): unknown {\n if (value == null) return value;\n if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) {\n return Object.fromEntries(value);\n }\n return value;\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 公开 API\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 获取嵌套属性的值\n *\n * 支持两种路径格式:\n * - 点分隔:data.user.name\n * - 括号索引:data.users[0].name(内部转为 data.users.0.name)\n */\nexport function getNestedValue(obj: unknown, path: string): unknown {\n if (!path) return obj;\n const normalized = path.replace(/\\[(\\d+)\\]/g, '.$1');\n return normalized.split('.').reduce<unknown>(\n (o: any, k) => (o == null ? undefined : o[k]),\n obj,\n );\n}\n\n/**\n * 解析字符串模板\n * 支持 ${xxx} 或 ${xxx.yyy} 或 ${xxx[0].yyy} 占位符\n */\nexport function resolveTemplate(template: string, config: AxiosRequestConfig): string {\n const context = {\n method: config.method?.toUpperCase() || 'GET',\n url: config.url || '',\n params: toPlain(config.params),\n data: toPlain(config.data),\n };\n\n return template.replace(/\\$\\{([^}]+)\\}/g, (_match, path) => {\n const value = getNestedValue(context, path);\n if (value == null) return '';\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n });\n}\n\n/**\n * 生成默认的 requestKey(method + url + params + data 的排序哈希)\n *\n * 自动剔除 params 和 data 中的 _ 字段(缓存破坏参数),\n * 避免重试时 key 不一致导致 deferred 链断裂。\n */\nexport function generateDefaultKey(config: AxiosRequestConfig): string {\n const parts = [\n config.method?.toUpperCase() || 'GET',\n config.url || '',\n config.params != null ? JSON.stringify(sortObject(stripCacheParam(toPlain(config.params)))) : '',\n config.data != null ? JSON.stringify(sortObject(stripCacheParam(toPlain(config.data)))) : '',\n ];\n return hash(parts.join('|'));\n}\n\n/**\n * 字符串哈希(FNV-1a 32-bit,兼容浏览器)\n */\nexport function hash(str: string): string {\n let h = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i);\n h = (h * 0x01000193) >>> 0;\n }\n return h.toString(16).padStart(8, '0');\n}\n\n/**\n * 解析 requestKey\n *\n * - 函数 → 直接调用\n * - 包含 ${ 的字符串 → 模板解析\n * - 其他字符串 → 原样返回\n * - 未提供 → 自动生成(method + url + params + data)\n */\nexport function resolveRequestKey(\n config: AxiosRequestConfig,\n keyTemplate?: string | ((config: AxiosRequestConfig, hash: (str: string) => string) => string),\n): string {\n if (!keyTemplate) return generateDefaultKey(config);\n\n if (typeof keyTemplate === 'function') {\n return keyTemplate(config, hash);\n }\n\n if (typeof keyTemplate === 'string' && keyTemplate.includes('${')) {\n return hash(resolveTemplate(keyTemplate, config));\n }\n\n return keyTemplate;\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 内部函数\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 剔除对象中的 _ 字段(缓存破坏参数,不应参与 key 生成)\n */\nfunction stripCacheParam(obj: unknown): unknown {\n if (obj == null || typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj;\n if (!isPlainObject(obj)) return obj;\n const { _, ...rest } = obj as Record<string, unknown>;\n return rest;\n}\n\n/**\n * 对对象键进行递归排序(保证相同数据产生相同哈希)\n *\n * 非 plain 对象(Blob / FormData / Date 等)直接返回原值,\n * 避免 Object.keys() 返回空数组导致哈希碰撞。\n */\nfunction sortObject(obj: unknown): unknown {\n if (obj == null || typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(sortObject);\n if (!isPlainObject(obj)) return obj;\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n sorted[key] = sortObject(obj[key]);\n }\n return sorted;\n}\n","/**\n * getFormData — 将任意数据转换为 FormData\n *\n * 转换规则:\n * - File / Blob → 字段名 'file'(可通过 fieldName 自定义)\n * - FileList → 遍历,每个文件字段名 'file'\n * - 数组 → 遍历每一项,所有值共用同一字段名\n * - 普通对象 → 遍历 entries,每个 key 作为字段名;嵌套对象用 . 连接\n * - string/number/boolean → 转字符串,字段名 'file'\n * - null / undefined → 跳过\n */\n\nimport { isPlainObject } from './common';\n\nfunction appendValue(fd: FormData, key: string, value: unknown): void {\n if (value == null) return;\n\n if (value instanceof File) {\n fd.append(key, value);\n } else if (value instanceof Blob) {\n fd.append(key, value);\n } else if (value instanceof Date) {\n fd.append(key, value.toISOString());\n } else if (Array.isArray(value)) {\n for (const item of value) {\n appendValue(fd, key, item);\n }\n } else if (isPlainObject(value)) {\n for (const [subKey, subValue] of Object.entries(value)) {\n appendValue(fd, `${key}.${subKey}`, subValue);\n }\n } else {\n fd.append(key, String(value));\n }\n}\n\nexport function getFormData(data: unknown, fieldName?: string): FormData {\n const fd = new FormData();\n if (data == null) return fd;\n\n // FileList — 不能使用 for-of 迭代,单独处理\n if (typeof FileList !== 'undefined' && data instanceof FileList) {\n const key = fieldName || 'file';\n for (let i = 0; i < data.length; i++) fd.append(key, data[i]);\n return fd;\n }\n\n // 顶层普通对象 — 使用对象自身的 key\n if (isPlainObject(data)) {\n for (const [key, value] of Object.entries(data)) {\n appendValue(fd, key, value);\n }\n return fd;\n }\n\n // 其余所有类型统一走 appendValue\n appendValue(fd, fieldName || 'file', data);\n return fd;\n}\n","/**\n * enhance-axios 类型定义\n */\n\n// 引入 axios 类型\nimport type { AxiosRequestConfig, AxiosError } from 'axios';\nimport type { RequestManager } from '../core/requestManager';\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 基础类型\n// ════════════════════════════════════════════════════════════════════════════════\n\nexport type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';\n\n/**\n * Content-Type 简化配置\n *\n * - 'json': application/json;charset=UTF-8\n * - 'form': application/x-www-form-urlencoded\n * - 'file': multipart/form-data(当 data 为 FormData 时不设置,交由浏览器自动处理)\n * - 其他字符串:直接用作 Content-Type 值\n */\nexport type ContentType = 'json' | 'form' | 'file' | (string & {});\n\nexport const CONTENT_TYPE_MAP: Record<string, string> = {\n json: 'application/json;charset=UTF-8',\n form: 'application/x-www-form-urlencoded',\n};\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 配置接口\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 防重复提交配置\n *\n * 用于防止用户在短时间内重复发送相同请求\n * 当检测到重复请求时,返回已有请求的 Promise,阻止当前请求继续执行\n */\nexport interface PreventDuplicateConfig {\n /** 是否启用防重复提交,默认 true */\n enabled?: boolean;\n /** 请求标识生成方式 */\n requestKey?: string | ((config: AxiosRequestConfig, hash: (str: string) => string) => string);\n /** 生效的 HTTP 方法,默认全部方法 */\n methods?: string[];\n /** 防重复时间窗口(ms),默认 1000 */\n intervalMs?: number;\n}\n\n/**\n * 取消请求配置\n *\n * 用于取消正在进行的相同请求,只保留最新发出的请求\n * 当检测到相同请求时,取消旧请求,继续执行当前请求\n */\nexport interface CancelRequestConfig {\n /** 是否启用取消请求,默认 true */\n enabled?: boolean;\n /** 请求标识生成方式 */\n requestKey?: string | ((config: AxiosRequestConfig, hash: (str: string) => string) => string);\n /** 生效的 HTTP 方法,默认全部方法 */\n methods?: string[];\n}\n\n/**\n * 失败重试配置\n *\n * 用于在请求失败时自动重试\n */\nexport interface RetryConfig {\n /** 是否启用重试,默认 true */\n enabled?: boolean;\n /** 重试次数,默认 3 */\n retries?: number;\n /** 初始重试延迟(ms),默认 1000 */\n retryDelay?: number;\n /** 重试条件判断函数 */\n retryCondition?: (error: AxiosError) => boolean;\n /** 是否启用指数退避,默认 true */\n exponential?: boolean;\n /** 最大延迟时间(ms),默认 30000 */\n maxDelay?: number;\n /** 生效的 HTTP 方法,默认全部方法 */\n methods?: string[];\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 内部类型\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * Pending 请求结构\n *\n * 用于存储正在进行的请求信息\n */\nexport interface PendingRequest {\n /** 请求标识 */\n key: string;\n /** 请求配置 */\n config: AxiosRequestConfig;\n /** AbortController,用于取消请求 */\n controller: AbortController;\n /** 请求的 Promise */\n promise: Promise<unknown>;\n /** 请求创建时间戳 */\n timestamp: number;\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 增强实例接口\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 增强实例 API\n *\n * 提供对增强功能的访问和控制\n */\nexport interface EnhanceInstance {\n /** 请求管理器 */\n requestManager: RequestManager;\n /** 取消所有 pending 请求 */\n clearAll: () => void;\n /** 取消指定请求 */\n cancelRequest: (key: string) => boolean;\n /** 获取请求状态 */\n getRequestStatus: (key: string) => PendingRequest | undefined;\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 配置联合类型(用于灵活的 API)\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 防重复配置联合类型\n *\n * 支持多种输入格式:\n * - boolean: 直接启用/禁用\n * - string: 设置 requestKey\n * - function: 设置 requestKey 生成函数\n * - number: 设置 intervalMs\n * - string[]: 设置 methods\n * - object: 完整配置对象\n */\nexport type PreventDuplicateOption =\n | PreventDuplicateConfig\n | boolean\n | string\n | ((config: AxiosRequestConfig, hash: (str: string) => string) => string)\n | number\n | string[];\n\n/**\n * 取消请求配置联合类型\n *\n * 支持多种输入格式(同上)\n */\nexport type CancelRequestOption =\n | CancelRequestConfig\n | boolean\n | string\n | ((config: AxiosRequestConfig, hash: (str: string) => string) => string)\n | string[];\n\n/**\n * 重试配置联合类型\n *\n * 支持多种输入格式:\n * - boolean: 启用/禁用\n * - number: 设置 retries\n * - number[]: 生成 retryCondition(匹配数组中状态码或网络错误)\n * - function: 设置 retryCondition\n * - object: 完整配置对象\n */\nexport type RetryOption =\n | RetryConfig\n | boolean\n | number\n | ((error: AxiosError) => boolean);\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 内部类型(归一化后的配置,可选字段已填充默认值)\n// ════════════════════════════════════════════════════════════════════════════════\n\ntype RequiredKeys<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;\n\nexport type InternalPreventConfig = RequiredKeys<PreventDuplicateConfig, 'enabled' | 'intervalMs'>;\n\nexport type InternalCancelConfig = RequiredKeys<CancelRequestConfig, 'enabled'>;\n\nexport type InternalRetryConfig = RequiredKeys<\n RetryConfig,\n 'enabled' | 'retries' | 'retryDelay' | 'retryCondition' | 'exponential' | 'maxDelay'\n>;\n\n// ════════════════════════════════════════════════════════════════════════════════\n// AxiosRequestConfig 扩展\n// ════════════════════════════════════════════════════════════════════════════════\n\n/**\n * 增强后的 AxiosRequestConfig\n *\n * 扩展了 preventDuplicate、cancelRequest 和 retry 字段\n */\nexport interface CreateEnhanceOptions extends AxiosRequestConfig {\n /** Content-Type 简化配置,默认 'json' */\n contentType?: ContentType;\n /** 防重复提交配置 */\n preventDuplicate?: PreventDuplicateOption;\n /** 取消请求配置 */\n cancelRequest?: CancelRequestOption;\n /** 重试配置 */\n retry?: RetryOption;\n /** 所有请求自动添加 _ 参数防止缓存,默认 true,仅 false 关闭 */\n needCacheBust?: boolean;\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 模块扩展\n// ════════════════════════════════════════════════════════════════════════════════\n\n// 扩展 axios 的 AxiosRequestConfig 类型\ndeclare module 'axios' {\n interface AxiosRequestConfig {\n /** Content-Type 简化配置,默认 'json' */\n contentType?: ContentType;\n /** 防重复提交配置 */\n preventDuplicate?: PreventDuplicateOption;\n /** 取消请求配置 */\n cancelRequest?: CancelRequestOption;\n /** 重试配置 */\n retry?: RetryOption;\n /** 所有请求自动添加 _ 参数防止缓存,默认 true,仅 false 关闭 */\n needCacheBust?: boolean;\n }\n}\n\n// ════════════════════════════════════════════════════════════════════════════════\n// 导出\n// ════════════════════════════════════════════════════════════════════════════════\n\nexport { RequestManager } from '../core/requestManager';","// 此文件由构建脚本自动生成,请勿手动修改\nexport const version = '1.0.2';\nexport default version;\n"],"mappings":"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","names":[]}
|