/** * @author Kuitos * @homepage https://github.com/kuitos/ * @since 2017-10-11 */ import { AxiosAdapter, AxiosPromise, AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios'; import Cache from './Cache'; import buildSortedURL from './utils/buildSortedURL'; import deleteCacheEntry from './utils/deleteCacheEntry'; import { ICacheLike } from './utils/isCacheLike'; import resolveAdapter from './utils/resolveAdapter'; import shouldLogInfo from './utils/shouldLogInfo'; declare module 'axios' { interface AxiosRequestConfig { threshold?: number; } } export type RecordedCache = { timestamp: number; value?: AxiosPromise; }; export type Options = { threshold?: number, cache?: ICacheLike, }; export default function throttleAdapterEnhancer(adapter: NonNullable, options: Options = {}): AxiosAdapter { const resolvedAdapter = resolveAdapter(adapter); const { threshold = 1000, cache = new Cache({ max: 10 }) } = options; function recordCacheWithRequest(index: string, config: InternalAxiosRequestConfig): AxiosPromise { const responsePromise = (async () => { try { const response = await resolvedAdapter(config); cache.set(index, { timestamp: Date.now(), value: Promise.resolve(response), }); return response; } catch (reason) { deleteCacheEntry(cache, index); throw reason; } })(); cache.set(index, { timestamp: Date.now(), value: responsePromise, }); return responsePromise; } return config => { const { url, method, params, paramsSerializer, threshold: thresholdPerRequest } = config; const index = buildSortedURL(url, params, paramsSerializer); const effectiveThreshold = thresholdPerRequest ?? threshold; const now = Date.now(); const cachedRecord = cache.get(index) || { timestamp: now }; if (method === 'get') { if (now - cachedRecord.timestamp <= effectiveThreshold) { const responsePromise = cachedRecord.value; if (responsePromise) { /* istanbul ignore next */ if (shouldLogInfo()) { console.info(`[axios-extensions] request cached by throttle adapter --> url: ${index}`); } return responsePromise; } } return recordCacheWithRequest(index, config); } return resolvedAdapter(config); }; }