mirror of
https://github.com/arthurfiorette/axios-cache-interceptor.git
synced 2025-12-08 17:36:16 +00:00
style: linted code
This commit is contained in:
parent
37e2f1e85a
commit
ecbc27e466
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
@ -6,14 +6,7 @@
|
|||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"runtimeExecutable": "pnpm",
|
"runtimeExecutable": "pnpm",
|
||||||
"runtimeArgs": [
|
"runtimeArgs": ["--inspect-brk", "jest", "--", "--runInBand", "--watch", "--coverage"],
|
||||||
"--inspect-brk",
|
|
||||||
"jest",
|
|
||||||
"--",
|
|
||||||
"--runInBand",
|
|
||||||
"--watch",
|
|
||||||
"--coverage"
|
|
||||||
],
|
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"internalConsoleOptions": "neverOpen"
|
"internalConsoleOptions": "neverOpen"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,7 @@ const VERSION = isVersion > -1 ? process.argv[isVersion + 1].slice(1, -1) : 'Lat
|
|||||||
const BASE_URL = isVersion > -1 ? process.argv[isVersion + 1] : '/';
|
const BASE_URL = isVersion > -1 ? process.argv[isVersion + 1] : '/';
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
isVersion > -1
|
isVersion > -1 ? `Building docs for version ${VERSION}` : 'Building docs for latest version'
|
||||||
? `Building docs for version ${VERSION}`
|
|
||||||
: 'Building docs for latest version'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const description =
|
const description =
|
||||||
@ -44,22 +42,10 @@ export default defineConfig({
|
|||||||
head: [
|
head: [
|
||||||
// Attach a custom favicon
|
// Attach a custom favicon
|
||||||
['link', { rel: 'icon', href: `${BASE_URL}favicon.ico', type: 'image/x-icon` }],
|
['link', { rel: 'icon', href: `${BASE_URL}favicon.ico', type: 'image/x-icon` }],
|
||||||
[
|
['link', { rel: 'apple-touch-icon', sizes: '57x57', href: `${BASE_URL}apple-icon-57x57.png` }],
|
||||||
'link',
|
['link', { rel: 'apple-touch-icon', sizes: '60x60', href: `${BASE_URL}apple-icon-60x60.png` }],
|
||||||
{ rel: 'apple-touch-icon', sizes: '57x57', href: `${BASE_URL}apple-icon-57x57.png` }
|
['link', { rel: 'apple-touch-icon', sizes: '72x72', href: `${BASE_URL}apple-icon-72x72.png` }],
|
||||||
],
|
['link', { rel: 'apple-touch-icon', sizes: '76x76', href: `${BASE_URL}apple-icon-76x76.png` }],
|
||||||
[
|
|
||||||
'link',
|
|
||||||
{ rel: 'apple-touch-icon', sizes: '60x60', href: `${BASE_URL}apple-icon-60x60.png` }
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'link',
|
|
||||||
{ rel: 'apple-touch-icon', sizes: '72x72', href: `${BASE_URL}apple-icon-72x72.png` }
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'link',
|
|
||||||
{ rel: 'apple-touch-icon', sizes: '76x76', href: `${BASE_URL}apple-icon-76x76.png` }
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'link',
|
'link',
|
||||||
{
|
{
|
||||||
@ -139,10 +125,7 @@ export default defineConfig({
|
|||||||
|
|
||||||
['link', { rel: 'manifest', href: `${BASE_URL}manifest.json` }],
|
['link', { rel: 'manifest', href: `${BASE_URL}manifest.json` }],
|
||||||
['meta', { name: 'msapplication-TileColor', content: '#e5972a' }],
|
['meta', { name: 'msapplication-TileColor', content: '#e5972a' }],
|
||||||
[
|
['meta', { name: 'msapplication-TileImage', content: `${BASE_URL}ms-icon-144x144.png` }],
|
||||||
'meta',
|
|
||||||
{ name: 'msapplication-TileImage', content: `${BASE_URL}ms-icon-144x144.png` }
|
|
||||||
],
|
|
||||||
['meta', { name: 'theme-color', content: '#e5972a' }],
|
['meta', { name: 'theme-color', content: '#e5972a' }],
|
||||||
['meta', { name: 'description', content: description }],
|
['meta', { name: 'description', content: description }],
|
||||||
|
|
||||||
@ -171,10 +154,7 @@ export default defineConfig({
|
|||||||
content: 'u9Nw6WpRrWDhdPTAv-LGIE9aJ0C15t7zkjuaUizDJnA'
|
content: 'u9Nw6WpRrWDhdPTAv-LGIE9aJ0C15t7zkjuaUizDJnA'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
['script', { async: 'true', src: 'https://www.googletagmanager.com/gtag/js?id=G-K548ZF395X' }],
|
||||||
'script',
|
|
||||||
{ async: 'true', src: 'https://www.googletagmanager.com/gtag/js?id=G-K548ZF395X' }
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'script',
|
'script',
|
||||||
{},
|
{},
|
||||||
@ -228,24 +208,21 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
|
|
||||||
nav: [
|
nav: [
|
||||||
{ text: 'Guide', link: `/guide` },
|
{ text: 'Guide', link: '/guide' },
|
||||||
{ text: 'Config', link: `/config` },
|
{ text: 'Config', link: '/config' },
|
||||||
{ text: 'Others', link: `/others/license` },
|
{ text: 'Others', link: '/others/license' },
|
||||||
{
|
{
|
||||||
text: VERSION,
|
text: VERSION,
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Latest', link: url },
|
{ text: 'Latest', link: url },
|
||||||
{ text: 'v0.x', link: `${url}/v0/` }
|
{ text: 'v0.x', link: `${url}/v0/` }
|
||||||
].filter((i) =>
|
].filter((i) => (BASE_URL === '/' ? i.text !== 'Latest' : !i.link.includes(BASE_URL)))
|
||||||
BASE_URL === '/' ? i.text !== 'Latest' : !i.link.includes(BASE_URL)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
//! Temp link for testing, will be changed to the real one before merged to production
|
//! Temp link for testing, will be changed to the real one before merged to production
|
||||||
editLink: {
|
editLink: {
|
||||||
pattern:
|
pattern: 'https://github.com/arthurfiorette/axios-cache-interceptor/edit/main/docs/src/:path'
|
||||||
'https://github.com/arthurfiorette/axios-cache-interceptor/edit/main/docs/src/:path'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
footer: {
|
footer: {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ const { log } = console;
|
|||||||
//
|
//
|
||||||
|
|
||||||
log(`Fetched response Cache-Control: ${fetchedResponse.headers['cache-control']}`);
|
log(`Fetched response Cache-Control: ${fetchedResponse.headers['cache-control']}`);
|
||||||
log(`Fetched response Age: ${fetchedResponse.headers['age']}`);
|
log(`Fetched response Age: ${fetchedResponse.headers.age}`);
|
||||||
|
|
||||||
const cacheInformation = await axios.storage.get(fetchedResponse.id);
|
const cacheInformation = await axios.storage.get(fetchedResponse.id);
|
||||||
|
|
||||||
|
|||||||
5
src/cache/axios.ts
vendored
5
src/cache/axios.ts
vendored
@ -5,7 +5,6 @@ import type {
|
|||||||
AxiosRequestConfig,
|
AxiosRequestConfig,
|
||||||
AxiosResponse,
|
AxiosResponse,
|
||||||
AxiosResponseHeaders,
|
AxiosResponseHeaders,
|
||||||
|
|
||||||
InternalAxiosRequestConfig
|
InternalAxiosRequestConfig
|
||||||
} from 'axios';
|
} from 'axios';
|
||||||
import type { CacheInstance, CacheProperties } from './cache';
|
import type { CacheInstance, CacheProperties } from './cache';
|
||||||
@ -84,8 +83,7 @@ export interface CacheRequestConfig<R = any, D = any> extends AxiosRequestConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Cached version of type {@link InternalAxiosRequestConfig} */
|
/** Cached version of type {@link InternalAxiosRequestConfig} */
|
||||||
export interface InternalCacheRequestConfig<R = any, D = any>
|
export interface InternalCacheRequestConfig<R = any, D = any> extends CacheRequestConfig<R, D> {
|
||||||
extends CacheRequestConfig<R, D> {
|
|
||||||
headers: AxiosResponseHeaders;
|
headers: AxiosResponseHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +94,6 @@ export interface InternalCacheRequestConfig<R = any, D = any>
|
|||||||
* @see https://axios-cache-interceptor.js.org/guide/getting-started
|
* @see https://axios-cache-interceptor.js.org/guide/getting-started
|
||||||
*/
|
*/
|
||||||
export interface AxiosCacheInstance extends CacheInstance, AxiosInstance {
|
export interface AxiosCacheInstance extends CacheInstance, AxiosInstance {
|
||||||
|
|
||||||
new (config?: CacheRequestConfig): AxiosCacheInstance;
|
new (config?: CacheRequestConfig): AxiosCacheInstance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
9
src/cache/create.ts
vendored
9
src/cache/create.ts
vendored
@ -26,10 +26,7 @@ export interface CacheOptions extends Partial<CacheInstance>, Partial<CachePrope
|
|||||||
* @returns The same instance with extended typescript types.
|
* @returns The same instance with extended typescript types.
|
||||||
* @see https://axios-cache-interceptor.js.org/config
|
* @see https://axios-cache-interceptor.js.org/config
|
||||||
*/
|
*/
|
||||||
export function setupCache(
|
export function setupCache(axios: AxiosInstance, options: CacheOptions = {}): AxiosCacheInstance {
|
||||||
axios: AxiosInstance,
|
|
||||||
options: CacheOptions = {}
|
|
||||||
): AxiosCacheInstance {
|
|
||||||
const axiosCache = axios as AxiosCacheInstance;
|
const axiosCache = axios as AxiosCacheInstance;
|
||||||
|
|
||||||
if (axiosCache.defaults.cache) {
|
if (axiosCache.defaults.cache) {
|
||||||
@ -54,7 +51,6 @@ export function setupCache(
|
|||||||
axiosCache.responseInterceptor =
|
axiosCache.responseInterceptor =
|
||||||
options.responseInterceptor || defaultResponseInterceptor(axiosCache);
|
options.responseInterceptor || defaultResponseInterceptor(axiosCache);
|
||||||
|
|
||||||
|
|
||||||
axiosCache.debug = options.debug || function noop() {};
|
axiosCache.debug = options.debug || function noop() {};
|
||||||
|
|
||||||
// CacheRequestConfig values
|
// CacheRequestConfig values
|
||||||
@ -69,8 +65,7 @@ export function setupCache(
|
|||||||
|
|
||||||
cachePredicate: options.cachePredicate || {
|
cachePredicate: options.cachePredicate || {
|
||||||
// All cacheable status codes defined in RFC 7231
|
// All cacheable status codes defined in RFC 7231
|
||||||
statusCheck: (status) =>
|
statusCheck: (status) => [200, 203, 300, 301, 302, 404, 405, 410, 414, 501].includes(status)
|
||||||
[200, 203, 300, 301, 302, 404, 405, 410, 414, 501].includes(status)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
etag: options.etag ?? true,
|
etag: options.etag ?? true,
|
||||||
|
|||||||
@ -34,6 +34,4 @@ export type InterpreterResult =
|
|||||||
* **milliseconds** to cache the response.
|
* **milliseconds** to cache the response.
|
||||||
* @see https://axios-cache-interceptor.js.org/config#headerinterpreter
|
* @see https://axios-cache-interceptor.js.org/config#headerinterpreter
|
||||||
*/
|
*/
|
||||||
export type HeaderInterpreter = (
|
export type HeaderInterpreter = (headers?: CacheAxiosResponse['headers']) => InterpreterResult;
|
||||||
headers?: CacheAxiosResponse['headers']
|
|
||||||
) => InterpreterResult;
|
|
||||||
|
|||||||
@ -10,7 +10,5 @@ export interface AxiosInterceptor<T> {
|
|||||||
apply: () => void;
|
apply: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RequestInterceptor = AxiosInterceptor<
|
export type RequestInterceptor = AxiosInterceptor<InternalCacheRequestConfig<unknown, unknown>>;
|
||||||
InternalCacheRequestConfig<unknown, unknown>
|
|
||||||
>;
|
|
||||||
export type ResponseInterceptor = AxiosInterceptor<CacheAxiosResponse<unknown, unknown>>;
|
export type ResponseInterceptor = AxiosInterceptor<CacheAxiosResponse<unknown, unknown>>;
|
||||||
|
|||||||
@ -1,18 +1,9 @@
|
|||||||
import { deferred } from 'fast-defer';
|
import { deferred } from 'fast-defer';
|
||||||
import type { AxiosCacheInstance, CacheAxiosResponse } from '../cache/axios';
|
import type { AxiosCacheInstance, CacheAxiosResponse } from '../cache/axios';
|
||||||
import { Header } from '../header/headers';
|
import { Header } from '../header/headers';
|
||||||
import type {
|
import type { CachedResponse, CachedStorageValue, LoadingStorageValue } from '../storage/types';
|
||||||
CachedResponse,
|
|
||||||
CachedStorageValue,
|
|
||||||
LoadingStorageValue
|
|
||||||
} from '../storage/types';
|
|
||||||
import type { RequestInterceptor } from './build';
|
import type { RequestInterceptor } from './build';
|
||||||
import {
|
import { ConfigWithCache, createValidateStatus, isMethodIn, updateStaleRequest } from './util';
|
||||||
ConfigWithCache,
|
|
||||||
createValidateStatus,
|
|
||||||
isMethodIn,
|
|
||||||
updateStaleRequest
|
|
||||||
} from './util';
|
|
||||||
|
|
||||||
export function defaultRequestInterceptor(axios: AxiosCacheInstance) {
|
export function defaultRequestInterceptor(axios: AxiosCacheInstance) {
|
||||||
const onFulfilled: RequestInterceptor['onFulfilled'] = async (config) => {
|
const onFulfilled: RequestInterceptor['onFulfilled'] = async (config) => {
|
||||||
@ -58,11 +49,7 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance) {
|
|||||||
|
|
||||||
// Not cached, continue the request, and mark it as fetching
|
// Not cached, continue the request, and mark it as fetching
|
||||||
// biome-ignore lint/suspicious/noConfusingLabels: required to break condition in simultaneous accesses
|
// biome-ignore lint/suspicious/noConfusingLabels: required to break condition in simultaneous accesses
|
||||||
ignoreAndRequest: if (
|
ignoreAndRequest: if (cache.state === 'empty' || cache.state === 'stale' || overrideCache) {
|
||||||
cache.state === 'empty' ||
|
|
||||||
cache.state === 'stale' ||
|
|
||||||
overrideCache
|
|
||||||
) {
|
|
||||||
/**
|
/**
|
||||||
* This checks for simultaneous access to a new key. The js event loop jumps on the
|
* This checks for simultaneous access to a new key. The js event loop jumps on the
|
||||||
* first await statement, so the second (asynchronous call) request may have already
|
* first await statement, so the second (asynchronous call) request may have already
|
||||||
@ -121,8 +108,7 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance) {
|
|||||||
|
|
||||||
// If the cache is empty and asked to override it, use the current timestamp
|
// If the cache is empty and asked to override it, use the current timestamp
|
||||||
|
|
||||||
createdAt:
|
createdAt: overrideCache && !cache.createdAt ? Date.now() : (cache.createdAt as any)
|
||||||
overrideCache && !cache.createdAt ? Date.now() : (cache.createdAt as any)
|
|
||||||
},
|
},
|
||||||
config
|
config
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,10 +1,6 @@
|
|||||||
import type { AxiosResponseHeaders } from 'axios';
|
import type { AxiosResponseHeaders } from 'axios';
|
||||||
import { parse } from 'cache-parser';
|
import { parse } from 'cache-parser';
|
||||||
import type {
|
import type { AxiosCacheInstance, CacheAxiosResponse, CacheRequestConfig } from '../cache/axios';
|
||||||
AxiosCacheInstance,
|
|
||||||
CacheAxiosResponse,
|
|
||||||
CacheRequestConfig
|
|
||||||
} from '../cache/axios';
|
|
||||||
import type { CacheProperties } from '../cache/cache';
|
import type { CacheProperties } from '../cache/cache';
|
||||||
import { Header } from '../header/headers';
|
import { Header } from '../header/headers';
|
||||||
import type { CachedStorageValue } from '../storage/types';
|
import type { CachedStorageValue } from '../storage/types';
|
||||||
@ -13,9 +9,7 @@ import { updateCache } from '../util/update-cache';
|
|||||||
import type { ResponseInterceptor } from './build';
|
import type { ResponseInterceptor } from './build';
|
||||||
import { createCacheResponse, isMethodIn } from './util';
|
import { createCacheResponse, isMethodIn } from './util';
|
||||||
|
|
||||||
export function defaultResponseInterceptor(
|
export function defaultResponseInterceptor(axios: AxiosCacheInstance): ResponseInterceptor {
|
||||||
axios: AxiosCacheInstance
|
|
||||||
): ResponseInterceptor {
|
|
||||||
/**
|
/**
|
||||||
* Rejects cache for an response response.
|
* Rejects cache for an response response.
|
||||||
*
|
*
|
||||||
@ -45,7 +39,6 @@ export function defaultResponseInterceptor(
|
|||||||
throw response;
|
throw response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
response.id = response.config.id!;
|
response.id = response.config.id!;
|
||||||
response.cached ??= false;
|
response.cached ??= false;
|
||||||
|
|
||||||
|
|||||||
@ -33,17 +33,13 @@ export interface ConfigWithCache<D> extends CacheRequestConfig<unknown, D> {
|
|||||||
* This function updates the cache when the request is stale. So, the next request to the
|
* This function updates the cache when the request is stale. So, the next request to the
|
||||||
* server will be made with proper header / settings.
|
* server will be made with proper header / settings.
|
||||||
*/
|
*/
|
||||||
export function updateStaleRequest<D>(
|
export function updateStaleRequest<D>(cache: StaleStorageValue, config: ConfigWithCache<D>): void {
|
||||||
cache: StaleStorageValue,
|
|
||||||
config: ConfigWithCache<D>
|
|
||||||
): void {
|
|
||||||
config.headers ||= {};
|
config.headers ||= {};
|
||||||
|
|
||||||
const { etag, modifiedSince } = config.cache;
|
const { etag, modifiedSince } = config.cache;
|
||||||
|
|
||||||
if (etag) {
|
if (etag) {
|
||||||
const etagValue =
|
const etagValue = etag === true ? (cache.data?.headers[Header.ETag] as unknown) : etag;
|
||||||
etag === true ? (cache.data?.headers[Header.ETag] as unknown) : etag;
|
|
||||||
|
|
||||||
if (etagValue) {
|
if (etagValue) {
|
||||||
config.headers[Header.IfNoneMatch] = etagValue;
|
config.headers[Header.IfNoneMatch] = etagValue;
|
||||||
|
|||||||
@ -1,20 +1,13 @@
|
|||||||
import type { CacheRequestConfig } from '../cache/axios';
|
import type { CacheRequestConfig } from '../cache/axios';
|
||||||
import { Header } from '../header/headers';
|
import { Header } from '../header/headers';
|
||||||
import type { MaybePromise } from '../util/types';
|
import type { MaybePromise } from '../util/types';
|
||||||
import type {
|
import type { AxiosStorage, CachedStorageValue, StaleStorageValue, StorageValue } from './types';
|
||||||
AxiosStorage,
|
|
||||||
CachedStorageValue,
|
|
||||||
StaleStorageValue,
|
|
||||||
StorageValue
|
|
||||||
} from './types';
|
|
||||||
|
|
||||||
/** Returns true if the provided object was created from {@link buildStorage} function. */
|
/** Returns true if the provided object was created from {@link buildStorage} function. */
|
||||||
export const isStorage = (obj: unknown): obj is AxiosStorage =>
|
export const isStorage = (obj: unknown): obj is AxiosStorage =>
|
||||||
!!obj && !!(obj as Record<string, boolean>)['is-storage'];
|
!!obj && !!(obj as Record<string, boolean>)['is-storage'];
|
||||||
|
|
||||||
function hasUniqueIdentifierHeader(
|
function hasUniqueIdentifierHeader(value: CachedStorageValue | StaleStorageValue): boolean {
|
||||||
value: CachedStorageValue | StaleStorageValue
|
|
||||||
): boolean {
|
|
||||||
const headers = value.data.headers;
|
const headers = value.data.headers;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -102,7 +95,7 @@ export interface BuildStorage extends Omit<AxiosStorage, 'get'> {
|
|||||||
export function buildStorage({ set, find, remove }: BuildStorage): AxiosStorage {
|
export function buildStorage({ set, find, remove }: BuildStorage): AxiosStorage {
|
||||||
return {
|
return {
|
||||||
//@ts-expect-error - we don't want to expose this
|
//@ts-expect-error - we don't want to expose this
|
||||||
['is-storage']: 1,
|
'is-storage': 1,
|
||||||
set,
|
set,
|
||||||
remove,
|
remove,
|
||||||
get: async (key, config) => {
|
get: async (key, config) => {
|
||||||
|
|||||||
@ -108,9 +108,9 @@ export function buildMemoryStorage(
|
|||||||
storage.cleanup = () => {
|
storage.cleanup = () => {
|
||||||
const keys = Object.keys(storage.data);
|
const keys = Object.keys(storage.data);
|
||||||
|
|
||||||
let i = -1,
|
let i = -1;
|
||||||
value: StorageValue,
|
let value: StorageValue;
|
||||||
key: string;
|
let key: string;
|
||||||
|
|
||||||
// Looping forward, as older entries are more likely to be expired
|
// Looping forward, as older entries are more likely to be expired
|
||||||
// than newer ones.
|
// than newer ones.
|
||||||
|
|||||||
@ -45,8 +45,7 @@ export function buildKeyGenerator<R = unknown, D = unknown>(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultKeyGenerator = buildKeyGenerator(
|
export const defaultKeyGenerator = buildKeyGenerator(({ baseURL, url, method, params, data }) => {
|
||||||
({ baseURL, url, method, params, data }) => {
|
|
||||||
// Remove trailing slashes to avoid generating different keys for the "same" final url.
|
// Remove trailing slashes to avoid generating different keys for the "same" final url.
|
||||||
if (baseURL !== undefined) {
|
if (baseURL !== undefined) {
|
||||||
baseURL = baseURL.replace(SLASHES_REGEX, '');
|
baseURL = baseURL.replace(SLASHES_REGEX, '');
|
||||||
@ -75,5 +74,4 @@ export const defaultKeyGenerator = buildKeyGenerator(
|
|||||||
method: method,
|
method: method,
|
||||||
data: data
|
data: data
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import type { CacheAxiosResponse, CacheRequestConfig } from '../cache/axios';
|
import type { CacheAxiosResponse, CacheRequestConfig } from '../cache/axios';
|
||||||
import type {
|
import type { CachedStorageValue, LoadingStorageValue, StorageValue } from '../storage/types';
|
||||||
CachedStorageValue,
|
|
||||||
LoadingStorageValue,
|
|
||||||
StorageValue
|
|
||||||
} from '../storage/types';
|
|
||||||
|
|
||||||
export type CachePredicate<R = unknown, D = unknown> = Exclude<
|
export type CachePredicate<R = unknown, D = unknown> = Exclude<
|
||||||
CachePredicateObject<R, D> | CachePredicateObject<R, D>['responseMatch'],
|
CachePredicateObject<R, D> | CachePredicateObject<R, D>['responseMatch'],
|
||||||
@ -35,9 +31,7 @@ export interface CachePredicateObject<R = unknown, D = unknown> {
|
|||||||
* A simple function that receives a cache request config and should return a string id
|
* A simple function that receives a cache request config and should return a string id
|
||||||
* for it.
|
* for it.
|
||||||
*/
|
*/
|
||||||
export type KeyGenerator<R = unknown, D = unknown> = (
|
export type KeyGenerator<R = unknown, D = unknown> = (options: CacheRequestConfig<R, D>) => string;
|
||||||
options: CacheRequestConfig<R, D>
|
|
||||||
) => string;
|
|
||||||
|
|
||||||
export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;
|
export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;
|
||||||
|
|
||||||
@ -58,9 +52,7 @@ export type StaleIfErrorPredicate<R, D> =
|
|||||||
error: Record<string, unknown>
|
error: Record<string, unknown>
|
||||||
) => MaybePromise<number | boolean>);
|
) => MaybePromise<number | boolean>);
|
||||||
|
|
||||||
export type CacheUpdaterFn<R, D> = (
|
export type CacheUpdaterFn<R, D> = (response: CacheAxiosResponse<R, D>) => MaybePromise<void>;
|
||||||
response: CacheAxiosResponse<R, D>
|
|
||||||
) => MaybePromise<void>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A record for a custom cache updater for each specified request id.
|
* A record for a custom cache updater for each specified request id.
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export async function updateCache<R, D>(
|
|||||||
cacheUpdater: CacheUpdater<R, D>
|
cacheUpdater: CacheUpdater<R, D>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Global cache update function.
|
// Global cache update function.
|
||||||
if (typeof cacheUpdater === `function`) {
|
if (typeof cacheUpdater === 'function') {
|
||||||
return cacheUpdater(data);
|
return cacheUpdater(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
test/cache/create.test.ts
vendored
2
test/cache/create.test.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
import Axios from 'axios';
|
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { describe, it, mock } from 'node:test';
|
import { describe, it, mock } from 'node:test';
|
||||||
|
import Axios from 'axios';
|
||||||
import { setupCache } from '../../src/cache/create';
|
import { setupCache } from '../../src/cache/create';
|
||||||
|
|
||||||
describe('Axios Cache Interceptor instances', () => {
|
describe('Axios Cache Interceptor instances', () => {
|
||||||
|
|||||||
@ -10,15 +10,9 @@ describe('Header Interpreter', () => {
|
|||||||
|
|
||||||
assert.equal(defaultHeaderInterpreter({}), 'not enough headers');
|
assert.equal(defaultHeaderInterpreter({}), 'not enough headers');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(defaultHeaderInterpreter({ [Header.CacheControl]: '' }), 'not enough headers');
|
||||||
defaultHeaderInterpreter({ [Header.CacheControl]: '' }),
|
|
||||||
'not enough headers'
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(defaultHeaderInterpreter({ 'x-random-header': '' }), 'not enough headers');
|
||||||
defaultHeaderInterpreter({ ['x-random-header']: '' }),
|
|
||||||
'not enough headers'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('MaxAge=10 and Age=3', () => {
|
it('MaxAge=10 and Age=3', () => {
|
||||||
|
|||||||
@ -73,10 +73,7 @@ describe('Hydrate handling', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Only hydrates when stale while revalidate is set', async () => {
|
it('Only hydrates when stale while revalidate is set', async () => {
|
||||||
const axios = mockAxios(
|
const axios = mockAxios({}, { [Header.CacheControl]: 'max-age=0, stale-while-revalidate=0' });
|
||||||
{},
|
|
||||||
{ [Header.CacheControl]: 'max-age=0, stale-while-revalidate=0' }
|
|
||||||
);
|
|
||||||
const id = 'some-unique-id';
|
const id = 'some-unique-id';
|
||||||
|
|
||||||
const m = mock.fn();
|
const m = mock.fn();
|
||||||
@ -98,10 +95,7 @@ describe('Hydrate handling', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Only hydrates when stale while revalidate is not expired', async () => {
|
it('Only hydrates when stale while revalidate is not expired', async () => {
|
||||||
const axios = mockAxios(
|
const axios = mockAxios({}, { [Header.CacheControl]: 'max-age=0, stale-while-revalidate=1' });
|
||||||
{},
|
|
||||||
{ [Header.CacheControl]: 'max-age=0, stale-while-revalidate=1' }
|
|
||||||
);
|
|
||||||
const id = 'some-unique-id';
|
const id = 'some-unique-id';
|
||||||
|
|
||||||
const m = mock.fn();
|
const m = mock.fn();
|
||||||
@ -126,7 +120,7 @@ describe('Hydrate handling', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Hydrates when force stale', async () => {
|
it('Hydrates when force stale', async () => {
|
||||||
const axios = mockAxios({}, { [Header.CacheControl]: `max-age=100` });
|
const axios = mockAxios({}, { [Header.CacheControl]: 'max-age=100' });
|
||||||
const id = 'some-unique-id';
|
const id = 'some-unique-id';
|
||||||
|
|
||||||
const m = mock.fn();
|
const m = mock.fn();
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
import type { AxiosAdapter, AxiosResponse } from 'axios';
|
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { describe, it, mock } from 'node:test';
|
import { describe, it, mock } from 'node:test';
|
||||||
|
import type { AxiosAdapter, AxiosResponse } from 'axios';
|
||||||
import { setTimeout } from 'timers/promises';
|
import { setTimeout } from 'timers/promises';
|
||||||
import type {
|
import type { CacheRequestConfig, InternalCacheRequestConfig } from '../../src/cache/axios';
|
||||||
CacheRequestConfig,
|
|
||||||
InternalCacheRequestConfig
|
|
||||||
} from '../../src/cache/axios';
|
|
||||||
import { Header } from '../../src/header/headers';
|
import { Header } from '../../src/header/headers';
|
||||||
import type { LoadingStorageValue } from '../../src/storage/types';
|
import type { LoadingStorageValue } from '../../src/storage/types';
|
||||||
import { mockAxios } from '../mocks/axios';
|
import { mockAxios } from '../mocks/axios';
|
||||||
@ -100,10 +97,7 @@ describe('Request Interceptor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Cache expiration', async () => {
|
it('Cache expiration', async () => {
|
||||||
const axios = mockAxios(
|
const axios = mockAxios({}, { [Header.CacheControl]: 'max-age=1,stale-while-revalidate=10' });
|
||||||
{},
|
|
||||||
{ [Header.CacheControl]: 'max-age=1,stale-while-revalidate=10' }
|
|
||||||
);
|
|
||||||
|
|
||||||
await axios.get('http://test.com', { cache: { interpretHeader: true } });
|
await axios.get('http://test.com', { cache: { interpretHeader: true } });
|
||||||
|
|
||||||
@ -240,9 +234,7 @@ describe('Request Interceptor', () => {
|
|||||||
adapter: async (config: InternalCacheRequestConfig) => {
|
adapter: async (config: InternalCacheRequestConfig) => {
|
||||||
await setTimeout(150);
|
await setTimeout(150);
|
||||||
|
|
||||||
const response = (await (axios.defaults.adapter as AxiosAdapter)(
|
const response = (await (axios.defaults.adapter as AxiosAdapter)(config)) as AxiosResponse;
|
||||||
config
|
|
||||||
)) as AxiosResponse;
|
|
||||||
|
|
||||||
// Changes the response to be different from `true` (default)
|
// Changes the response to be different from `true` (default)
|
||||||
response.data = 'overridden response';
|
response.data = 'overridden response';
|
||||||
@ -347,7 +339,7 @@ describe('Request Interceptor', () => {
|
|||||||
|
|
||||||
assert.deepEqual(Object.assign({}, req1.request.config.headers), {
|
assert.deepEqual(Object.assign({}, req1.request.config.headers), {
|
||||||
[Header.CacheControl]: 'no-cache',
|
[Header.CacheControl]: 'no-cache',
|
||||||
['Accept']: 'application/json, text/plain, */*',
|
Accept: 'application/json, text/plain, */*',
|
||||||
'Content-Type': undefined,
|
'Content-Type': undefined,
|
||||||
[Header.Pragma]: 'no-cache',
|
[Header.Pragma]: 'no-cache',
|
||||||
[Header.Expires]: '0'
|
[Header.Expires]: '0'
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import Axios from 'axios';
|
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { describe, it, mock } from 'node:test';
|
import { describe, it, mock } from 'node:test';
|
||||||
import { setImmediate } from 'node:timers/promises';
|
import { setImmediate } from 'node:timers/promises';
|
||||||
|
import Axios from 'axios';
|
||||||
import { setupCache } from '../../src/cache/create';
|
import { setupCache } from '../../src/cache/create';
|
||||||
import { Header } from '../../src/header/headers';
|
import { Header } from '../../src/header/headers';
|
||||||
import { XMockRandom, mockAxios } from '../mocks/axios';
|
import { XMockRandom, mockAxios } from '../mocks/axios';
|
||||||
@ -92,10 +92,7 @@ describe('Response Interceptor', () => {
|
|||||||
|
|
||||||
assert.equal(resultNoCache.cached, false);
|
assert.equal(resultNoCache.cached, false);
|
||||||
|
|
||||||
const axiosCache = mockAxios(
|
const axiosCache = mockAxios({}, { [Header.CacheControl]: `max-age=${60 * 60 * 24 * 365}` });
|
||||||
{},
|
|
||||||
{ [Header.CacheControl]: `max-age=${60 * 60 * 24 * 365}` }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Make first request to cache it
|
// Make first request to cache it
|
||||||
await axiosCache.get('http://test.com', { cache: { interpretHeader: true } });
|
await axiosCache.get('http://test.com', { cache: { interpretHeader: true } });
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Axios, { AxiosError } from 'axios';
|
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { describe, it } from 'node:test';
|
import { describe, it } from 'node:test';
|
||||||
|
import Axios, { AxiosError } from 'axios';
|
||||||
import { setupCache } from '../../src/cache/create';
|
import { setupCache } from '../../src/cache/create';
|
||||||
import { Header } from '../../src/header/headers';
|
import { Header } from '../../src/header/headers';
|
||||||
import { mockAxios } from '../mocks/axios';
|
import { mockAxios } from '../mocks/axios';
|
||||||
@ -431,7 +431,7 @@ describe('StaleIfError handling', () => {
|
|||||||
|
|
||||||
const id = 'arthurfiorette/axios-cache-interceptor#685';
|
const id = 'arthurfiorette/axios-cache-interceptor#685';
|
||||||
|
|
||||||
let data = await axios.get('url', { id });
|
const data = await axios.get('url', { id });
|
||||||
|
|
||||||
assert.equal(data.cached, false);
|
assert.equal(data.cached, false);
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Axios from 'axios';
|
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { describe, it } from 'node:test';
|
import { describe, it } from 'node:test';
|
||||||
|
import Axios from 'axios';
|
||||||
import { createValidateStatus, isMethodIn } from '../../src/interceptors/util';
|
import { createValidateStatus, isMethodIn } from '../../src/interceptors/util';
|
||||||
import { mockAxios } from '../mocks/axios';
|
import { mockAxios } from '../mocks/axios';
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import Axios, { AxiosError } from 'axios';
|
|
||||||
import { setTimeout } from 'node:timers/promises';
|
import { setTimeout } from 'node:timers/promises';
|
||||||
|
import Axios, { AxiosError } from 'axios';
|
||||||
import type { AxiosCacheInstance } from '../../src/cache/axios';
|
import type { AxiosCacheInstance } from '../../src/cache/axios';
|
||||||
import { CacheOptions, setupCache } from '../../src/cache/create';
|
import { CacheOptions, setupCache } from '../../src/cache/create';
|
||||||
import { Header } from '../../src/header/headers';
|
import { Header } from '../../src/header/headers';
|
||||||
|
|||||||
@ -30,7 +30,7 @@ describe('MemoryStorage', () => {
|
|||||||
assert.equal(result.data.data, 'data');
|
assert.equal(result.data.data, 'data');
|
||||||
|
|
||||||
// Deletes the value
|
// Deletes the value
|
||||||
delete result.data.data;
|
result.data.data = undefined;
|
||||||
|
|
||||||
// Check if the value has been modified
|
// Check if the value has been modified
|
||||||
const result2 = await storage.get('key');
|
const result2 = await storage.get('key');
|
||||||
@ -58,10 +58,10 @@ describe('MemoryStorage', () => {
|
|||||||
|
|
||||||
data.data = 'another data';
|
data.data = 'another data';
|
||||||
|
|
||||||
assert.notEqual(storage.data['key'], null);
|
assert.notEqual(storage.data.key, null);
|
||||||
assert.equal(storage.data['key']!.state, 'cached');
|
assert.equal(storage.data.key!.state, 'cached');
|
||||||
assert.notEqual(storage.data['key']!.data, null);
|
assert.notEqual(storage.data.key!.data, null);
|
||||||
assert.equal(storage.data['key']!.data!.data, 'data');
|
assert.equal(storage.data.key!.data!.data, 'data');
|
||||||
|
|
||||||
const result = (await storage.get('key')) as CachedStorageValue;
|
const result = (await storage.get('key')) as CachedStorageValue;
|
||||||
|
|
||||||
@ -118,12 +118,12 @@ describe('MemoryStorage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Ensure that the values are still there
|
// Ensure that the values are still there
|
||||||
assert.equal(storage.data['empty']?.state, 'empty');
|
assert.equal(storage.data.empty?.state, 'empty');
|
||||||
assert.equal(storage.data['stale']?.state, 'stale');
|
assert.equal(storage.data.stale?.state, 'stale');
|
||||||
assert.equal(storage.data['expiredStale']?.state, 'stale');
|
assert.equal(storage.data.expiredStale?.state, 'stale');
|
||||||
assert.equal(storage.data['loading']?.state, 'loading');
|
assert.equal(storage.data.loading?.state, 'loading');
|
||||||
assert.equal(storage.data['cached']?.state, 'cached');
|
assert.equal(storage.data.cached?.state, 'cached');
|
||||||
assert.equal(storage.data['expiredCache']?.state, 'cached');
|
assert.equal(storage.data.expiredCache?.state, 'cached');
|
||||||
|
|
||||||
// Waits for the cleanup function to run
|
// Waits for the cleanup function to run
|
||||||
await mockDateNow(600);
|
await mockDateNow(600);
|
||||||
@ -157,9 +157,9 @@ describe('MemoryStorage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(Object.keys(storage.data).length, 2);
|
assert.equal(Object.keys(storage.data).length, 2);
|
||||||
assert.ok(storage.data['key']);
|
assert.ok(storage.data.key);
|
||||||
assert.ok(storage.data['key2']);
|
assert.ok(storage.data.key2);
|
||||||
assert.equal(storage.data['key3'], undefined);
|
assert.equal(storage.data.key3, undefined);
|
||||||
|
|
||||||
await storage.set('key3', {
|
await storage.set('key3', {
|
||||||
state: 'cached',
|
state: 'cached',
|
||||||
@ -170,9 +170,9 @@ describe('MemoryStorage', () => {
|
|||||||
|
|
||||||
assert.equal(Object.keys(storage.data).length, 2);
|
assert.equal(Object.keys(storage.data).length, 2);
|
||||||
|
|
||||||
assert.equal(storage.data['key'], undefined);
|
assert.equal(storage.data.key, undefined);
|
||||||
assert.ok(storage.data['key2']);
|
assert.ok(storage.data.key2);
|
||||||
assert.ok(storage.data['key3']);
|
assert.ok(storage.data.key3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tests maxEntries with cleanup', async () => {
|
it('tests maxEntries with cleanup', async () => {
|
||||||
@ -200,10 +200,10 @@ describe('MemoryStorage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(Object.keys(storage.data).length, 3);
|
assert.equal(Object.keys(storage.data).length, 3);
|
||||||
assert.ok(storage.data['exp']);
|
assert.ok(storage.data.exp);
|
||||||
assert.ok(storage.data['not exp']);
|
assert.ok(storage.data['not exp']);
|
||||||
assert.ok(storage.data['exp2']);
|
assert.ok(storage.data.exp2);
|
||||||
assert.equal(storage.data['key'], undefined);
|
assert.equal(storage.data.key, undefined);
|
||||||
|
|
||||||
await storage.set('key', {
|
await storage.set('key', {
|
||||||
state: 'cached',
|
state: 'cached',
|
||||||
@ -214,9 +214,9 @@ describe('MemoryStorage', () => {
|
|||||||
|
|
||||||
assert.equal(Object.keys(storage.data).length, 2);
|
assert.equal(Object.keys(storage.data).length, 2);
|
||||||
|
|
||||||
assert.equal(storage.data['exp'], undefined);
|
assert.equal(storage.data.exp, undefined);
|
||||||
assert.equal(storage.data['exp2'], undefined);
|
assert.equal(storage.data.exp2, undefined);
|
||||||
assert.ok(storage.data['not exp']);
|
assert.ok(storage.data['not exp']);
|
||||||
assert.ok(storage.data['key']);
|
assert.ok(storage.data.key);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Axios } from 'axios';
|
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { describe, it } from 'node:test';
|
import { describe, it } from 'node:test';
|
||||||
|
import { Axios } from 'axios';
|
||||||
import { buildStorage, canStale, isStorage } from '../../src/storage/build';
|
import { buildStorage, canStale, isStorage } from '../../src/storage/build';
|
||||||
import { buildMemoryStorage } from '../../src/storage/memory';
|
import { buildMemoryStorage } from '../../src/storage/memory';
|
||||||
import type { AxiosStorage, StorageValue } from '../../src/storage/types';
|
import type { AxiosStorage, StorageValue } from '../../src/storage/types';
|
||||||
|
|||||||
@ -127,10 +127,7 @@ describe('CachePredicate', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
await testCachePredicate(
|
await testCachePredicate(response, ({ data }) => data && data.a === true && data.b === 1)
|
||||||
response,
|
|
||||||
({ data }) => data && data.a === true && data.b === 1
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
@ -224,10 +221,7 @@ describe('CachePredicate', () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
id: (
|
id: (_, { data: { a, b }, headers, status, statusText }): CachedStorageValue => {
|
||||||
_,
|
|
||||||
{ data: { a, b }, headers, status, statusText }
|
|
||||||
): CachedStorageValue => {
|
|
||||||
return {
|
return {
|
||||||
state: 'cached',
|
state: 'cached',
|
||||||
ttl: Number.MAX_SAFE_INTEGER,
|
ttl: Number.MAX_SAFE_INTEGER,
|
||||||
|
|||||||
@ -101,10 +101,7 @@ describe('KeyGeneration', () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (const [first, second] of groups) {
|
for (const [first, second] of groups) {
|
||||||
assert.equal(
|
assert.equal(defaultKeyGenerator({ url: first }), defaultKeyGenerator({ url: second }));
|
||||||
defaultKeyGenerator({ url: first }),
|
|
||||||
defaultKeyGenerator({ url: second })
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
defaultKeyGenerator({ baseURL: first }),
|
defaultKeyGenerator({ baseURL: first }),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { AxiosHeaders } from 'axios';
|
|
||||||
import { mock } from 'node:test';
|
import { mock } from 'node:test';
|
||||||
|
import { AxiosHeaders } from 'axios';
|
||||||
import type { CacheAxiosResponse } from '../src/cache/axios';
|
import type { CacheAxiosResponse } from '../src/cache/axios';
|
||||||
|
|
||||||
export const EMPTY_RESPONSE = Object.freeze({
|
export const EMPTY_RESPONSE = Object.freeze({
|
||||||
@ -9,9 +9,7 @@ export const EMPTY_RESPONSE = Object.freeze({
|
|||||||
data: true
|
data: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export function createResponse<R>(
|
export function createResponse<R>(config: Partial<CacheAxiosResponse<R>>): CacheAxiosResponse {
|
||||||
config: Partial<CacheAxiosResponse<R>>
|
|
||||||
): CacheAxiosResponse {
|
|
||||||
return {
|
return {
|
||||||
...EMPTY_RESPONSE,
|
...EMPTY_RESPONSE,
|
||||||
config: { headers: new AxiosHeaders() },
|
config: { headers: new AxiosHeaders() },
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user