From 098cf47d06b70b966852f7dfb4747c8eaee2b14a Mon Sep 17 00:00:00 2001 From: arthurfiorette Date: Sun, 23 Jan 2022 18:12:14 -0300 Subject: [PATCH] refactor: added debug points --- docs/pages/installing.md | 8 +-- src/cache/cache.ts | 8 ++- src/interceptors/request.ts | 58 +++++++++++++++++- src/interceptors/response.ts | 110 ++++++++++++++++++++++++++++++++++- 4 files changed, 176 insertions(+), 8 deletions(-) diff --git a/docs/pages/installing.md b/docs/pages/installing.md index 41c6a1e..3d845fa 100644 --- a/docs/pages/installing.md +++ b/docs/pages/installing.md @@ -36,10 +36,6 @@ const { setupCache } = require('axios-cache-interceptor/umd'); ## With CDN -```js -const { setupCache } = window.AxiosCacheInterceptor; -``` - ```html ``` +```js +const { setupCache } = window.AxiosCacheInterceptor; +``` + ## With URL imports You can import any [CDN Url](#with-cdns) and use it in your code. **UMD Compatible** diff --git a/src/cache/cache.ts b/src/cache/cache.ts index 9141250..57032bf 100644 --- a/src/cache/cache.ts +++ b/src/cache/cache.ts @@ -163,5 +163,11 @@ export interface CacheInstance { * @default console.log * @see https://axios-cache-interceptor.js.org/#/pages/development-mode */ - debug: Console['log'] | undefined; + debug: undefined | ((msg: DebugObject) => void); } + +/** + * An object with any possible type that can be used to log and debug information in + * `development` mode (a.k.a `__ACI_DEV__ === true`) + */ +export type DebugObject = Partial<{ id: string; msg: string; data: unknown }>; diff --git a/src/interceptors/request.ts b/src/interceptors/request.ts index f83f6ea..edc1692 100644 --- a/src/interceptors/request.ts +++ b/src/interceptors/request.ts @@ -16,6 +16,13 @@ import { export function defaultRequestInterceptor(axios: AxiosCacheInstance) { const onFulfilled: RequestInterceptor['onFulfilled'] = async (config) => { if (config.cache === false) { + if (__ACI_DEV__) { + axios.debug?.({ + msg: 'Ignoring cache because config.cache is false', + data: config + }); + } + return config; } @@ -23,6 +30,11 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance) { config.cache = { ...axios.defaults.cache, ...config.cache }; if (!isMethodIn(config.method, config.cache.methods)) { + if (__ACI_DEV__) { + axios.debug?.({ + msg: `Ignored because method (${config.method}) is not in cache.methods (${config.cache.methods})` + }); + } return config; } @@ -42,6 +54,14 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance) { cache = (await axios.storage.get(key)) as | CachedStorageValue | LoadingStorageValue; + + if (__ACI_DEV__) { + axios.debug?.({ + id: key, + msg: 'Waiting list had an deferred for this key, waiting for it to finish' + }); + } + break emptyOrStale; } @@ -67,10 +87,24 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance) { if (cache.state === 'stale') { updateStaleRequest(cache, config as ConfigWithCache); + + if (__ACI_DEV__) { + axios.debug?.({ + id: key, + msg: 'Updated stale request' + }); + } } config.validateStatus = createValidateStatus(config.validateStatus); + if (__ACI_DEV__) { + axios.debug?.({ + id: key, + msg: 'Sending request, waiting for response' + }); + } + return config; } @@ -86,9 +120,24 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance) { return config; } + if (__ACI_DEV__) { + axios.debug?.({ + id: key, + msg: 'Detected concurrent request, waiting for it to finish' + }); + } + try { cachedResponse = await deferred; - } catch { + } catch (err) { + if (__ACI_DEV__) { + axios.debug?.({ + id: key, + msg: 'Deferred rejected, requesting again', + data: err + }); + } + // The deferred is rejected when the request that we are waiting rejected cache. return config; } @@ -109,6 +158,13 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance) { id: key }); + if (__ACI_DEV__) { + axios.debug?.({ + id: key, + msg: 'Returning cached response' + }); + } + return config; }; diff --git a/src/interceptors/response.ts b/src/interceptors/response.ts index cd1b35e..ca25d53 100644 --- a/src/interceptors/response.ts +++ b/src/interceptors/response.ts @@ -33,12 +33,27 @@ export function defaultResponseInterceptor( // Response is already cached if (response.cached) { + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: 'Returned cached response' + }); + } + return response; } // Skip cache: either false or weird behavior // config.cache should always exists, at least from global config merge. if (!response.config.cache) { + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: 'Response with config.cache === false', + data: response + }); + } + return { ...response, cached: false }; } @@ -54,6 +69,14 @@ export function defaultResponseInterceptor( // Should not hit here because of previous response.cached check cache.state === 'cached' ) { + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: 'Response not cached but storage is not loading', + data: { cache, response } + }); + } + return response; } @@ -64,6 +87,13 @@ export function defaultResponseInterceptor( !(await testCachePredicate(response, cacheConfig.cachePredicate)) ) { await rejectResponse(response.id); + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: 'Cache predicate rejected this response' + }); + } + return response; } @@ -95,6 +125,19 @@ export function defaultResponseInterceptor( // Cache should not be used if (expirationTime === 'dont cache') { await rejectResponse(response.id); + + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: `Cache header interpreted as 'dont cache'`, + data: { + cache, + response, + expirationTime + } + }); + } + return response; } @@ -111,6 +154,14 @@ export function defaultResponseInterceptor( response.headers[Header.XAxiosCacheStaleIfError] = String(ttl); } + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: 'Useful response configuration found', + data: { cacheConfig, ttl, cacheResponse: data } + }); + } + // Update other entries before updating himself if (cacheConfig?.update) { await updateCache(axios.storage, response, cacheConfig.update); @@ -124,12 +175,31 @@ export function defaultResponseInterceptor( }; // Resolve all other requests waiting for this response - axios.waiting[response.id]?.resolve(newCache.data); - delete axios.waiting[response.id]; + const waiting = axios.waiting[response.id]; + if (waiting) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + waiting.resolve(newCache.data); + delete axios.waiting[response.id]; + + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: 'Found waiting deferred(s) and resolved them' + }); + } + } // Define this key as cache on the storage await axios.storage.set(response.id, newCache); + if (__ACI_DEV__) { + axios.debug?.({ + id: response.id, + msg: 'Response cached', + data: { cache: newCache, response } + }); + } + // Return the response with cached as false, because it was not cached at all return response; }; @@ -138,6 +208,13 @@ export function defaultResponseInterceptor( const config = error['config'] as CacheRequestConfig; if (!config || config.cache === false || !config.id) { + if (__ACI_DEV__) { + axios.debug?.({ + msg: 'Web request returned an error but cache handling is not enabled', + data: { error, config } + }); + } + throw error; } @@ -150,6 +227,14 @@ export function defaultResponseInterceptor( cache.previous !== 'stale' ) { await rejectResponse(config.id); + + if (__ACI_DEV__) { + axios.debug?.({ + msg: 'Caught an error in the request interceptor', + data: { error, config } + }); + } + throw error; } @@ -163,6 +248,13 @@ export function defaultResponseInterceptor( ) : cacheConfig.staleIfError; + if (__ACI_DEV__) { + axios.debug?.({ + msg: 'Found cache if stale config for rejected response', + data: { error, config, staleIfError } + }); + } + if ( staleIfError === true || // staleIfError is the number of seconds that stale is allowed to be used @@ -179,6 +271,13 @@ export function defaultResponseInterceptor( data: cache.data }); + if (__ACI_DEV__) { + axios.debug?.({ + msg: 'staleIfError resolved this response with cached data', + data: { error, config, cache } + }); + } + return { cached: true, config, @@ -191,6 +290,13 @@ export function defaultResponseInterceptor( } } + if (__ACI_DEV__) { + axios.debug?.({ + msg: 'Received an unknown error that could not be handled', + data: { error, config } + }); + } + throw error; };