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;
};