-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy patherror-cache.ts
122 lines (111 loc) · 4.13 KB
/
error-cache.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { lru } from 'tiny-lru';
// @ts-ignore
import { XiorError, joinPath, isAbsoluteURL, buildSortedURL } from 'xior';
import { ICacheLike } from './utils';
import type { XiorPlugin, XiorRequestConfig, XiorResponse } from '../types';
export type XiorErrorCacheOptions = {
/**
* check if we need enable cache, default only `GET` method or`isGet: true` enable cache @error-cache-plugin
*/
enableCache?: boolean | ((config?: XiorRequestConfig) => boolean);
defaultCache?: ICacheLike<{ loading?: boolean; res?: XiorResponse; cacheTime?: number }>;
/** if `useCacheFirst: true` and have cache, will return the cache response first, then run fetching in the background @error-cache-plugin */
useCacheFirst?: boolean;
/** for logging purpose @error-cache-plugin */
onCacheRequest?: (config?: XiorRequestConfig) => void;
/** max cache numbers in LRU, default is 100 */
cacheItems?: number;
};
/** @ts-ignore */
declare module 'xior' {
interface XiorRequestConfig extends Omit<XiorErrorCacheOptions, 'cacheItems'> {
//
}
interface XiorResponse {
fromCache?: boolean;
error?: XiorError;
cacheTime?: number;
}
}
export default function xiorErrorCachePlugin(options: XiorErrorCacheOptions = {}): XiorPlugin {
const {
enableCache: _enableCache,
defaultCache: _defaultCache = lru<{
loading?: boolean;
res?: XiorResponse;
cacheTime?: number;
}>(options.cacheItems || 100),
useCacheFirst: _inBg,
onCacheRequest: _cacheRequest,
} = options;
return function (adapter) {
return async (config) => {
const {
enableCache = _enableCache,
defaultCache = _defaultCache,
useCacheFirst = _inBg,
onCacheRequest = _cacheRequest,
paramsSerializer,
} = config as XiorErrorCacheOptions & XiorRequestConfig;
const isGet = config.method === 'GET' || config.isGet;
const t = typeof enableCache;
let enabled: boolean | undefined = undefined;
if (t === 'function') {
enabled = (enableCache as (config: XiorRequestConfig) => boolean | undefined)(config);
}
if (enabled === undefined) {
enabled = t === 'undefined' ? isGet : Boolean(enableCache);
}
if (!enabled) return adapter(config);
const cache = defaultCache;
const index = buildSortedURL(
config.url && isAbsoluteURL(config.url) ? config.url : joinPath(config.baseURL, config.url),
{ a: config.data, b: config.params },
paramsSerializer as (obj: Record<string, any>) => string
);
try {
if (useCacheFirst) {
const result = cache.get(index);
cache.set(index, { loading: true, res: result?.res, cacheTime: result?.cacheTime });
if (result?.res) {
if (!result?.loading) {
onCacheRequest?.(config);
(async () => {
try {
const res = await adapter(config);
cache.set(index, { loading: false, res, cacheTime: Date.now() });
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
const result = cache.get(index);
if (useCacheFirst)
cache.set(index, {
loading: false,
res: result?.res,
cacheTime: result?.cacheTime,
});
}
})();
}
(result as any).res.fromCache = true;
(result as any).res.cacheTime = result?.cacheTime;
return result?.res;
}
}
const res = await adapter(config);
cache.set(index, { loading: false, res, cacheTime: Date.now() });
return res;
} catch (e) {
const result = cache.get(index);
if (useCacheFirst)
cache.set(index, { loading: false, res: result?.res, cacheTime: result?.cacheTime });
if (result?.res) {
(result as any).res.fromCache = true;
(result as any).res.error = e;
(result as any).res.cacheTime = result?.cacheTime;
return result.res;
}
throw e;
}
};
};
}