limited-cache 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/cjs/index.cjs +273 -380
- package/dist/cjs/index.d.cts +91 -76
- package/dist/cjs/index.d.cts.map +1 -0
- package/dist/esm/index.d.ts +106 -6
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +279 -6
- package/dist/esm/index.js.map +1 -1
- package/package.json +34 -53
- package/src/__tests__/LimitedCache.test.ts +2 -2
- package/src/__tests__/LimitedCacheObject.test.ts +30 -27
- package/src/__tests__/lowLevelFunctions.test.ts +10 -8
- package/src/__tests__/scenarios/keys.test.ts +2 -2
- package/src/__tests__/scenarios/maxCacheSize.test.ts +8 -5
- package/src/__tests__/scenarios/maxCacheTime.test.ts +58 -58
- package/src/__tests__/scenarios/values.test.ts +2 -2
- package/src/__tests__/typeChecks/LimitedCacheObjectTypes.test.ts +15 -15
- package/src/__tests__/typeChecks/LimitedCacheTypes.test.ts +1 -1
- package/src/__tests__/typeChecks/lowLevelFunctionsTypes.test.ts +2 -2
- package/src/core/LimitedCache.ts +20 -21
- package/src/core/LimitedCacheObject.ts +30 -19
- package/src/core/defaultOptions.ts +5 -4
- package/src/core/limitedCacheUtil.ts +15 -3
- package/src/core/lowLevelFunctions.ts +41 -32
- package/src/types.ts +16 -3
- package/dist/esm/core/LimitedCache.d.ts +0 -4
- package/dist/esm/core/LimitedCache.d.ts.map +0 -1
- package/dist/esm/core/LimitedCache.js +0 -29
- package/dist/esm/core/LimitedCache.js.map +0 -1
- package/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/dist/esm/core/LimitedCacheObject.d.ts.map +0 -1
- package/dist/esm/core/LimitedCacheObject.js +0 -52
- package/dist/esm/core/LimitedCacheObject.js.map +0 -1
- package/dist/esm/core/builtIns.d.ts +0 -12
- package/dist/esm/core/builtIns.d.ts.map +0 -1
- package/dist/esm/core/builtIns.js +0 -5
- package/dist/esm/core/builtIns.js.map +0 -1
- package/dist/esm/core/defaultOptions.d.ts +0 -6
- package/dist/esm/core/defaultOptions.d.ts.map +0 -1
- package/dist/esm/core/defaultOptions.js +0 -14
- package/dist/esm/core/defaultOptions.js.map +0 -1
- package/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/dist/esm/core/limitedCacheUtil.d.ts.map +0 -1
- package/dist/esm/core/limitedCacheUtil.js +0 -14
- package/dist/esm/core/limitedCacheUtil.js.map +0 -1
- package/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/dist/esm/core/lowLevelFunctions.d.ts.map +0 -1
- package/dist/esm/core/lowLevelFunctions.js +0 -240
- package/dist/esm/core/lowLevelFunctions.js.map +0 -1
- package/dist/esm/types.d.ts +0 -58
- package/dist/esm/types.d.ts.map +0 -1
- package/dist/esm/types.js +0 -2
- package/dist/esm/types.js.map +0 -1
- package/legacy-types/ts3.5/dist/esm/core/LimitedCache.d.ts +0 -4
- package/legacy-types/ts3.5/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/legacy-types/ts3.5/dist/esm/core/builtIns.d.ts +0 -12
- package/legacy-types/ts3.5/dist/esm/core/defaultOptions.d.ts +0 -6
- package/legacy-types/ts3.5/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/legacy-types/ts3.5/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/legacy-types/ts3.5/dist/esm/index.d.ts +0 -7
- package/legacy-types/ts3.5/dist/esm/types.d.ts +0 -61
- package/legacy-types/ts4.0/dist/esm/core/LimitedCache.d.ts +0 -4
- package/legacy-types/ts4.0/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/legacy-types/ts4.0/dist/esm/core/builtIns.d.ts +0 -12
- package/legacy-types/ts4.0/dist/esm/core/defaultOptions.d.ts +0 -6
- package/legacy-types/ts4.0/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/legacy-types/ts4.0/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/legacy-types/ts4.0/dist/esm/index.d.ts +0 -7
- package/legacy-types/ts4.0/dist/esm/types.d.ts +0 -61
- package/legacy-types/ts4.5/dist/esm/core/LimitedCache.d.ts +0 -4
- package/legacy-types/ts4.5/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/legacy-types/ts4.5/dist/esm/core/builtIns.d.ts +0 -12
- package/legacy-types/ts4.5/dist/esm/core/defaultOptions.d.ts +0 -6
- package/legacy-types/ts4.5/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/legacy-types/ts4.5/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/legacy-types/ts4.5/dist/esm/index.d.ts +0 -7
- package/legacy-types/ts4.5/dist/esm/types.d.ts +0 -61
- package/src/core/builtIns.ts +0 -9
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,403 +1,296 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var __spreadValues = (a, b) => {
|
|
12
|
-
for (var prop in b || (b = {}))
|
|
13
|
-
if (__hasOwnProp.call(b, prop))
|
|
14
|
-
__defNormalProp(a, prop, b[prop]);
|
|
15
|
-
if (__getOwnPropSymbols)
|
|
16
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
17
|
-
if (__propIsEnum.call(b, prop))
|
|
18
|
-
__defNormalProp(a, prop, b[prop]);
|
|
19
|
-
}
|
|
20
|
-
return a;
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/core/defaultOptions.ts
|
|
3
|
+
const CURRENT_META_VERSION = 2;
|
|
4
|
+
const MAXIMUM_CACHE_TIME = 365 * 86400 * 1e3;
|
|
5
|
+
const defaultOptions = {
|
|
6
|
+
maxCacheSize: 100,
|
|
7
|
+
maxCacheTime: 86400 * 1e3,
|
|
8
|
+
warnIfItemPurgedBeforeTime: 5e3,
|
|
9
|
+
opLimit: 200,
|
|
10
|
+
scanLimit: 50
|
|
21
11
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/core/lowLevelFunctions.ts
|
|
14
|
+
const positiveNumberOrZero = (value) => Math.max(value, 0) || 0;
|
|
15
|
+
const normalizeOptions = (cacheMetaOptions) => {
|
|
16
|
+
Object.assign(cacheMetaOptions, {
|
|
17
|
+
maxCacheSize: positiveNumberOrZero(cacheMetaOptions.maxCacheSize),
|
|
18
|
+
maxCacheTime: positiveNumberOrZero(cacheMetaOptions.maxCacheTime),
|
|
19
|
+
opLimit: positiveNumberOrZero(cacheMetaOptions.opLimit)
|
|
20
|
+
});
|
|
21
|
+
if (process.env.NODE_ENV !== "production") cacheMetaOptions.warnIfItemPurgedBeforeTime = positiveNumberOrZero(cacheMetaOptions.warnIfItemPurgedBeforeTime);
|
|
22
|
+
return cacheMetaOptions;
|
|
26
23
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for (let key of __getOwnPropNames(from))
|
|
30
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
31
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
32
|
-
}
|
|
33
|
-
return to;
|
|
24
|
+
const isCacheMeta = (cacheMeta) => {
|
|
25
|
+
return !!cacheMeta?.limitedCacheMetaVersion;
|
|
34
26
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
LimitedCacheObject: () => LimitedCacheObject,
|
|
43
|
-
MAXIMUM_CACHE_TIME: () => MAXIMUM_CACHE_TIME,
|
|
44
|
-
defaultOptions: () => defaultOptions,
|
|
45
|
-
getCacheMetaFromObject: () => getCacheMetaFromObject,
|
|
46
|
-
isCacheMeta: () => isCacheMeta,
|
|
47
|
-
limitedCacheUtil: () => limitedCacheUtil,
|
|
48
|
-
lowLevelDoMaintenance: () => lowLevelDoMaintenance,
|
|
49
|
-
lowLevelGetAll: () => lowLevelGetAll,
|
|
50
|
-
lowLevelGetOne: () => lowLevelGetOne,
|
|
51
|
-
lowLevelHas: () => lowLevelHas,
|
|
52
|
-
lowLevelInit: () => lowLevelInit,
|
|
53
|
-
lowLevelRemove: () => lowLevelRemove,
|
|
54
|
-
lowLevelReset: () => lowLevelReset,
|
|
55
|
-
lowLevelSet: () => lowLevelSet,
|
|
56
|
-
lowLevelSetOptions: () => lowLevelSetOptions,
|
|
57
|
-
upgradeCacheMeta: () => upgradeCacheMeta
|
|
58
|
-
});
|
|
59
|
-
module.exports = __toCommonJS(src_exports);
|
|
60
|
-
|
|
61
|
-
// src/core/defaultOptions.ts
|
|
62
|
-
var CURRENT_META_VERSION = 2;
|
|
63
|
-
var MAXIMUM_CACHE_TIME = 365 * 86400 * 1e3;
|
|
64
|
-
var defaultOptions = {
|
|
65
|
-
// Public
|
|
66
|
-
maxCacheSize: 100,
|
|
67
|
-
maxCacheTime: 86400 * 1e3,
|
|
68
|
-
// Development-only
|
|
69
|
-
warnIfItemPurgedBeforeTime: 5e3,
|
|
70
|
-
// Private
|
|
71
|
-
opLimit: 200,
|
|
72
|
-
scanLimit: 50
|
|
27
|
+
const upgradeCacheMeta = (cacheMeta) => {
|
|
28
|
+
if (!isCacheMeta(cacheMeta)) throw new Error("Limited-cache metadata is missing: please check your usage");
|
|
29
|
+
if (cacheMeta.limitedCacheMetaVersion !== 2) {
|
|
30
|
+
console.warn("Limited-cache metadata is from an incompatible version (1). It must be reset.");
|
|
31
|
+
cacheMeta.limitedCacheMetaVersion = 2;
|
|
32
|
+
lowLevelReset(cacheMeta);
|
|
33
|
+
}
|
|
73
34
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
create: objectCreate,
|
|
78
|
-
assign: objectAssign,
|
|
79
|
-
prototype: { hasOwnProperty }
|
|
80
|
-
} = Object;
|
|
81
|
-
var dateNow = Date.now;
|
|
82
|
-
|
|
83
|
-
// src/core/lowLevelFunctions.ts
|
|
84
|
-
var positiveNumberOrZero = (value) => Math.max(value, 0) || 0;
|
|
85
|
-
var normalizeOptions = (cacheMetaOptions) => {
|
|
86
|
-
objectAssign(cacheMetaOptions, {
|
|
87
|
-
maxCacheSize: positiveNumberOrZero(cacheMetaOptions.maxCacheSize),
|
|
88
|
-
maxCacheTime: positiveNumberOrZero(cacheMetaOptions.maxCacheTime),
|
|
89
|
-
opLimit: positiveNumberOrZero(cacheMetaOptions.opLimit)
|
|
90
|
-
});
|
|
91
|
-
if (process.env.NODE_ENV !== "production") {
|
|
92
|
-
cacheMetaOptions.warnIfItemPurgedBeforeTime = positiveNumberOrZero(
|
|
93
|
-
cacheMetaOptions.warnIfItemPurgedBeforeTime
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
return cacheMetaOptions;
|
|
35
|
+
const lowLevelSetOptions = (cacheMeta, options) => {
|
|
36
|
+
upgradeCacheMeta(cacheMeta);
|
|
37
|
+
return normalizeOptions(Object.assign(cacheMeta.options, options));
|
|
97
38
|
};
|
|
98
|
-
|
|
99
|
-
|
|
39
|
+
const lowLevelInit = (optionsOrCacheMeta) => {
|
|
40
|
+
if (isCacheMeta(optionsOrCacheMeta)) {
|
|
41
|
+
const existingCacheMeta = optionsOrCacheMeta;
|
|
42
|
+
upgradeCacheMeta(existingCacheMeta);
|
|
43
|
+
return existingCacheMeta;
|
|
44
|
+
}
|
|
45
|
+
return lowLevelReset({
|
|
46
|
+
limitedCacheMetaVersion: 2,
|
|
47
|
+
options: normalizeOptions({
|
|
48
|
+
...defaultOptions,
|
|
49
|
+
...optionsOrCacheMeta
|
|
50
|
+
})
|
|
51
|
+
});
|
|
100
52
|
};
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
console.warn("Limited-cache metadata is from an incompatible version (1). It must be reset.");
|
|
107
|
-
cacheMeta.limitedCacheMetaVersion = CURRENT_META_VERSION;
|
|
108
|
-
lowLevelReset(cacheMeta);
|
|
109
|
-
}
|
|
53
|
+
const _getExpireTime = (cacheMeta, cacheKey) => {
|
|
54
|
+
const { options: { maxCacheTime }, keyInfo: { [cacheKey]: keyInfo } } = cacheMeta;
|
|
55
|
+
if (!keyInfo) return 0;
|
|
56
|
+
const [setTime, expireTime] = keyInfo;
|
|
57
|
+
return expireTime || setTime + (maxCacheTime || 31536e6);
|
|
110
58
|
};
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return normalizeOptions(objectAssign(cacheMeta.options, options));
|
|
59
|
+
const _cacheKeyHasExpired = (cacheMeta, cacheKey, now) => {
|
|
60
|
+
return _getExpireTime(cacheMeta, cacheKey) < now;
|
|
114
61
|
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
62
|
+
const lowLevelDoMaintenance = (cacheMeta) => {
|
|
63
|
+
upgradeCacheMeta(cacheMeta);
|
|
64
|
+
const { cache, keyList, keyInfo } = cacheMeta;
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
const [newCache, newKeyList, newKeyInfo] = keyList.reduce((acc, cacheKey) => {
|
|
67
|
+
const [accCache, accKeyList, accKeyInfo] = acc;
|
|
68
|
+
if (!_cacheKeyHasExpired(cacheMeta, cacheKey, now)) {
|
|
69
|
+
accCache[cacheKey] = cache[cacheKey];
|
|
70
|
+
accKeyList.push(cacheKey);
|
|
71
|
+
accKeyInfo[cacheKey] = keyInfo[cacheKey];
|
|
72
|
+
}
|
|
73
|
+
return acc;
|
|
74
|
+
}, [
|
|
75
|
+
{},
|
|
76
|
+
[],
|
|
77
|
+
Object.create(null)
|
|
78
|
+
]);
|
|
79
|
+
return Object.assign(cacheMeta, {
|
|
80
|
+
cache: newCache,
|
|
81
|
+
keyList: newKeyList,
|
|
82
|
+
keyInfo: newKeyInfo,
|
|
83
|
+
opsLeft: cacheMeta.options.opLimit
|
|
84
|
+
});
|
|
127
85
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
86
|
+
const _removeFromIndex = (cacheMeta, startIndex, now) => {
|
|
87
|
+
const { cache, keyList, keyInfo } = cacheMeta;
|
|
88
|
+
let nextIndex = startIndex;
|
|
89
|
+
let nextCacheKey = keyList[startIndex];
|
|
90
|
+
const keyListLength = keyList.length;
|
|
91
|
+
do {
|
|
92
|
+
cache[nextCacheKey] = keyInfo[nextCacheKey] = void 0;
|
|
93
|
+
nextIndex++;
|
|
94
|
+
nextCacheKey = keyList[nextIndex];
|
|
95
|
+
} while (nextIndex < keyListLength && _cacheKeyHasExpired(cacheMeta, nextCacheKey, now));
|
|
96
|
+
keyList.splice(startIndex, nextIndex - startIndex);
|
|
138
97
|
};
|
|
139
|
-
|
|
140
|
-
|
|
98
|
+
const _removeItemsToMakeRoom = (cacheMeta, now) => {
|
|
99
|
+
const { options: { scanLimit, warnIfItemPurgedBeforeTime }, cache, keyList, keyInfo } = cacheMeta;
|
|
100
|
+
let oldestItemIndex = 0;
|
|
101
|
+
let oldestExpireTime = _getExpireTime(cacheMeta, keyList[0]);
|
|
102
|
+
if (oldestExpireTime > now) {
|
|
103
|
+
let indexToCheck = 0;
|
|
104
|
+
const maxIndexToCheck = Math.min(keyList.length, scanLimit);
|
|
105
|
+
while (indexToCheck < maxIndexToCheck) {
|
|
106
|
+
const cacheKeyForIndex = keyList[indexToCheck];
|
|
107
|
+
const expireTimeForIndex = _getExpireTime(cacheMeta, cacheKeyForIndex);
|
|
108
|
+
if (expireTimeForIndex < now) {
|
|
109
|
+
oldestItemIndex = indexToCheck;
|
|
110
|
+
oldestExpireTime = 0;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
if (expireTimeForIndex < oldestExpireTime) {
|
|
114
|
+
oldestItemIndex = indexToCheck;
|
|
115
|
+
oldestExpireTime = expireTimeForIndex;
|
|
116
|
+
}
|
|
117
|
+
indexToCheck += 1;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (process.env.NODE_ENV !== "production" && warnIfItemPurgedBeforeTime && oldestExpireTime > now) {
|
|
121
|
+
const oldestItemKey = keyList[oldestItemIndex];
|
|
122
|
+
const [oldestItemSetTime, oldestItemExpireTime] = keyInfo[oldestItemKey];
|
|
123
|
+
if (now - oldestItemSetTime < warnIfItemPurgedBeforeTime) console.warn("Purged an item from cache while it was still fresh: you may want to increase maxCacheSize", {
|
|
124
|
+
currentTime: now,
|
|
125
|
+
key: oldestItemKey,
|
|
126
|
+
item: cache[oldestItemKey],
|
|
127
|
+
setTime: oldestItemSetTime,
|
|
128
|
+
expireTime: oldestItemExpireTime,
|
|
129
|
+
timeInCache: now - oldestItemSetTime
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
_removeFromIndex(cacheMeta, oldestItemIndex, now);
|
|
141
133
|
};
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
accCache[cacheKey] = cache[cacheKey];
|
|
151
|
-
accKeyList.push(cacheKey);
|
|
152
|
-
accKeyInfo[cacheKey] = keyInfo[cacheKey];
|
|
153
|
-
}
|
|
154
|
-
return acc;
|
|
155
|
-
},
|
|
156
|
-
[
|
|
157
|
-
{},
|
|
158
|
-
[],
|
|
159
|
-
objectCreate(null)
|
|
160
|
-
]
|
|
161
|
-
);
|
|
162
|
-
return objectAssign(cacheMeta, {
|
|
163
|
-
cache: newCache,
|
|
164
|
-
keyList: newKeyList,
|
|
165
|
-
keyInfo: newKeyInfo,
|
|
166
|
-
opsLeft: cacheMeta.options.opLimit
|
|
167
|
-
});
|
|
134
|
+
const lowLevelHas = (cacheMeta, cacheKey) => {
|
|
135
|
+
upgradeCacheMeta(cacheMeta);
|
|
136
|
+
const { cache } = cacheMeta;
|
|
137
|
+
if (Object.prototype.hasOwnProperty.call(cache, cacheKey) && cache[cacheKey] !== void 0) {
|
|
138
|
+
if (!_cacheKeyHasExpired(cacheMeta, cacheKey, Date.now())) return true;
|
|
139
|
+
cache[cacheKey] = void 0;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
168
142
|
};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
let nextCacheKey = keyList[startIndex];
|
|
173
|
-
const keyListLength = keyList.length;
|
|
174
|
-
do {
|
|
175
|
-
cache[nextCacheKey] = keyInfo[nextCacheKey] = void 0;
|
|
176
|
-
nextIndex++;
|
|
177
|
-
nextCacheKey = keyList[nextIndex];
|
|
178
|
-
} while (nextIndex < keyListLength && _cacheKeyHasExpired(cacheMeta, nextCacheKey, now));
|
|
179
|
-
keyList.splice(startIndex, nextIndex - startIndex);
|
|
143
|
+
const lowLevelGetOne = (cacheMeta, cacheKey) => {
|
|
144
|
+
upgradeCacheMeta(cacheMeta);
|
|
145
|
+
if (lowLevelHas(cacheMeta, cacheKey)) return cacheMeta.cache[cacheKey];
|
|
180
146
|
};
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
keyList,
|
|
186
|
-
keyInfo
|
|
187
|
-
} = cacheMeta;
|
|
188
|
-
let oldestItemIndex = 0;
|
|
189
|
-
let oldestExpireTime = _getExpireTime(cacheMeta, keyList[0]);
|
|
190
|
-
if (oldestExpireTime > now) {
|
|
191
|
-
let indexToCheck = 0;
|
|
192
|
-
const maxIndexToCheck = Math.min(keyList.length, scanLimit);
|
|
193
|
-
while (indexToCheck < maxIndexToCheck) {
|
|
194
|
-
const cacheKeyForIndex = keyList[indexToCheck];
|
|
195
|
-
const expireTimeForIndex = _getExpireTime(cacheMeta, cacheKeyForIndex);
|
|
196
|
-
if (expireTimeForIndex < now) {
|
|
197
|
-
oldestItemIndex = indexToCheck;
|
|
198
|
-
oldestExpireTime = 0;
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
if (expireTimeForIndex < oldestExpireTime) {
|
|
202
|
-
oldestItemIndex = indexToCheck;
|
|
203
|
-
oldestExpireTime = expireTimeForIndex;
|
|
204
|
-
}
|
|
205
|
-
indexToCheck += 1;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (process.env.NODE_ENV !== "production" && warnIfItemPurgedBeforeTime && oldestExpireTime > now) {
|
|
209
|
-
const oldestItemKey = keyList[oldestItemIndex];
|
|
210
|
-
const [oldestItemSetTime, oldestItemExpireTime] = keyInfo[oldestItemKey];
|
|
211
|
-
if (now - oldestItemSetTime < warnIfItemPurgedBeforeTime) {
|
|
212
|
-
console.warn(
|
|
213
|
-
"Purged an item from cache while it was still fresh: you may want to increase maxCacheSize",
|
|
214
|
-
{
|
|
215
|
-
currentTime: now,
|
|
216
|
-
key: oldestItemKey,
|
|
217
|
-
item: cache[oldestItemKey],
|
|
218
|
-
setTime: oldestItemSetTime,
|
|
219
|
-
expireTime: oldestItemExpireTime,
|
|
220
|
-
timeInCache: now - oldestItemSetTime
|
|
221
|
-
}
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
_removeFromIndex(cacheMeta, oldestItemIndex, now);
|
|
147
|
+
const lowLevelGetAll = (cacheMeta) => {
|
|
148
|
+
upgradeCacheMeta(cacheMeta);
|
|
149
|
+
lowLevelDoMaintenance(cacheMeta);
|
|
150
|
+
return cacheMeta.cache;
|
|
226
151
|
};
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
152
|
+
const lowLevelSet = (cacheMeta, cacheKey, item) => {
|
|
153
|
+
upgradeCacheMeta(cacheMeta);
|
|
154
|
+
const { options: { maxCacheSize }, keyList, keyInfo } = cacheMeta;
|
|
155
|
+
const now = Date.now();
|
|
156
|
+
const isNew = !keyInfo[cacheKey];
|
|
157
|
+
if (cacheMeta.cache[cacheKey] !== item) cacheMeta.cache = {
|
|
158
|
+
...cacheMeta.cache,
|
|
159
|
+
[cacheKey]: item
|
|
160
|
+
};
|
|
161
|
+
keyInfo[cacheKey] = [now, 0];
|
|
162
|
+
if (isNew) {
|
|
163
|
+
keyList.push(cacheKey);
|
|
164
|
+
cacheMeta.opsLeft--;
|
|
165
|
+
if (cacheMeta.opsLeft <= 0) lowLevelDoMaintenance(cacheMeta);
|
|
166
|
+
if (maxCacheSize && cacheMeta.keyList.length > maxCacheSize) _removeItemsToMakeRoom(cacheMeta, now);
|
|
167
|
+
}
|
|
168
|
+
if (_cacheKeyHasExpired(cacheMeta, keyList[0], now)) _removeFromIndex(cacheMeta, 0, now);
|
|
169
|
+
return cacheMeta;
|
|
237
170
|
};
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
171
|
+
const lowLevelRemove = (cacheMeta, cacheKey) => {
|
|
172
|
+
upgradeCacheMeta(cacheMeta);
|
|
173
|
+
const { cache, keyInfo } = cacheMeta;
|
|
174
|
+
if (keyInfo[cacheKey]) {
|
|
175
|
+
if (cache[cacheKey] !== void 0) cacheMeta.cache = {
|
|
176
|
+
...cache,
|
|
177
|
+
[cacheKey]: void 0
|
|
178
|
+
};
|
|
179
|
+
keyInfo[cacheKey] = void 0;
|
|
180
|
+
}
|
|
181
|
+
return cacheMeta;
|
|
244
182
|
};
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
183
|
+
const lowLevelReset = (cacheMeta) => {
|
|
184
|
+
upgradeCacheMeta(cacheMeta);
|
|
185
|
+
return Object.assign(cacheMeta, {
|
|
186
|
+
cache: {},
|
|
187
|
+
keyList: [],
|
|
188
|
+
keyInfo: Object.create(null),
|
|
189
|
+
opsLeft: cacheMeta.options.opLimit
|
|
190
|
+
});
|
|
249
191
|
};
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (_cacheKeyHasExpired(cacheMeta, keyList[0], now)) {
|
|
276
|
-
_removeFromIndex(cacheMeta, 0, now);
|
|
277
|
-
}
|
|
278
|
-
return cacheMeta;
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/core/LimitedCache.ts
|
|
194
|
+
const bindFunctionToCacheMeta = (fn, cacheMeta) => fn.bind(null, cacheMeta);
|
|
195
|
+
const LimitedCache = (options) => {
|
|
196
|
+
const cacheMeta = lowLevelInit(options);
|
|
197
|
+
return {
|
|
198
|
+
get: bindFunctionToCacheMeta(lowLevelGetOne, cacheMeta),
|
|
199
|
+
getAll: bindFunctionToCacheMeta(lowLevelGetAll, cacheMeta),
|
|
200
|
+
has: bindFunctionToCacheMeta(lowLevelHas, cacheMeta),
|
|
201
|
+
set: (cacheKey, item) => {
|
|
202
|
+
lowLevelSet(cacheMeta, cacheKey, item);
|
|
203
|
+
return item;
|
|
204
|
+
},
|
|
205
|
+
remove: (cacheKey) => {
|
|
206
|
+
lowLevelRemove(cacheMeta, cacheKey);
|
|
207
|
+
return true;
|
|
208
|
+
},
|
|
209
|
+
reset: bindFunctionToCacheMeta(lowLevelReset, cacheMeta),
|
|
210
|
+
getCacheMeta: () => cacheMeta,
|
|
211
|
+
getOptions: () => cacheMeta.options,
|
|
212
|
+
setOptions: bindFunctionToCacheMeta(lowLevelSetOptions, cacheMeta),
|
|
213
|
+
doMaintenance: bindFunctionToCacheMeta(lowLevelDoMaintenance, cacheMeta)
|
|
214
|
+
};
|
|
279
215
|
};
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/core/LimitedCacheObject.ts
|
|
218
|
+
const proxyHandler = {
|
|
219
|
+
get: (cacheMeta, cacheKey) => {
|
|
220
|
+
if (cacheKey === "hasOwnProperty") return Object.prototype.hasOwnProperty;
|
|
221
|
+
return lowLevelGetOne(cacheMeta, cacheKey);
|
|
222
|
+
},
|
|
223
|
+
getOwnPropertyDescriptor: (cacheMeta, cacheKey) => {
|
|
224
|
+
const hasResult = lowLevelHas(cacheMeta, cacheKey);
|
|
225
|
+
const getResult = lowLevelGetOne(cacheMeta, cacheKey);
|
|
226
|
+
if (hasResult) return {
|
|
227
|
+
configurable: true,
|
|
228
|
+
enumerable: hasResult,
|
|
229
|
+
value: getResult,
|
|
230
|
+
writable: true
|
|
231
|
+
};
|
|
232
|
+
},
|
|
233
|
+
has: lowLevelHas,
|
|
234
|
+
set: (cacheMeta, cacheKey, item) => {
|
|
235
|
+
lowLevelSet(cacheMeta, cacheKey, item);
|
|
236
|
+
return item;
|
|
237
|
+
},
|
|
238
|
+
deleteProperty: (cacheMeta, cacheKey) => {
|
|
239
|
+
lowLevelRemove(cacheMeta, cacheKey);
|
|
240
|
+
return true;
|
|
241
|
+
},
|
|
242
|
+
ownKeys: (cacheMeta) => Object.keys(lowLevelGetAll(cacheMeta))
|
|
292
243
|
};
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
opsLeft: cacheMeta.options.opLimit
|
|
300
|
-
});
|
|
244
|
+
/**
|
|
245
|
+
* TypeScript's Proxy type models the runtime target, but LimitedCacheObject intentionally returns
|
|
246
|
+
* a facade with a different surface from the internal cache metadata target.
|
|
247
|
+
*/
|
|
248
|
+
const internal_createLimitedCacheObjectProxy = (cacheMeta) => {
|
|
249
|
+
return new Proxy(cacheMeta, proxyHandler);
|
|
301
250
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
lowLevelSet(cacheMeta, cacheKey, item);
|
|
313
|
-
return item;
|
|
314
|
-
},
|
|
315
|
-
remove: (cacheKey) => {
|
|
316
|
-
lowLevelRemove(cacheMeta, cacheKey);
|
|
317
|
-
return true;
|
|
318
|
-
},
|
|
319
|
-
reset: bindFunctionToCacheMeta(lowLevelReset, cacheMeta),
|
|
320
|
-
getCacheMeta: () => cacheMeta,
|
|
321
|
-
getOptions: () => cacheMeta.options,
|
|
322
|
-
setOptions: bindFunctionToCacheMeta(lowLevelSetOptions, cacheMeta),
|
|
323
|
-
doMaintenance: bindFunctionToCacheMeta(lowLevelDoMaintenance, cacheMeta)
|
|
324
|
-
};
|
|
251
|
+
/**
|
|
252
|
+
* So that we can retrieve the cacheMeta for a LimitedCacheObject, without polluting its properties, each proxy
|
|
253
|
+
* is associated back to its internal cacheMeta here.
|
|
254
|
+
*/
|
|
255
|
+
const cacheMetasForProxies = /* @__PURE__ */ new WeakMap();
|
|
256
|
+
const LimitedCacheObject = (options) => {
|
|
257
|
+
const cacheMeta = lowLevelInit(options);
|
|
258
|
+
const limitedCacheObject = internal_createLimitedCacheObjectProxy(cacheMeta);
|
|
259
|
+
cacheMetasForProxies.set(limitedCacheObject, cacheMeta);
|
|
260
|
+
return limitedCacheObject;
|
|
325
261
|
};
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
var proxyHandler = {
|
|
329
|
-
get: (cacheMeta, cacheKey) => {
|
|
330
|
-
if (cacheKey === "hasOwnProperty") {
|
|
331
|
-
return hasOwnProperty;
|
|
332
|
-
}
|
|
333
|
-
return lowLevelGetOne(cacheMeta, cacheKey);
|
|
334
|
-
},
|
|
335
|
-
getOwnPropertyDescriptor: (cacheMeta, cacheKey) => {
|
|
336
|
-
const hasResult = lowLevelHas(cacheMeta, cacheKey);
|
|
337
|
-
const getResult = lowLevelGetOne(cacheMeta, cacheKey);
|
|
338
|
-
if (hasResult) {
|
|
339
|
-
return {
|
|
340
|
-
configurable: true,
|
|
341
|
-
enumerable: hasResult,
|
|
342
|
-
value: getResult,
|
|
343
|
-
writable: true
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
return;
|
|
347
|
-
},
|
|
348
|
-
has: lowLevelHas,
|
|
349
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
350
|
-
set: (cacheMeta, cacheKey, item) => {
|
|
351
|
-
lowLevelSet(cacheMeta, cacheKey, item);
|
|
352
|
-
return item;
|
|
353
|
-
},
|
|
354
|
-
deleteProperty: (cacheMeta, cacheKey) => {
|
|
355
|
-
lowLevelRemove(cacheMeta, cacheKey);
|
|
356
|
-
return true;
|
|
357
|
-
},
|
|
358
|
-
ownKeys: (cacheMeta) => Object.keys(lowLevelGetAll(cacheMeta))
|
|
262
|
+
const getCacheMetaFromObject = (instance) => {
|
|
263
|
+
return cacheMetasForProxies.get(instance);
|
|
359
264
|
};
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/core/limitedCacheUtil.ts
|
|
267
|
+
const limitedCacheUtil = {
|
|
268
|
+
init: lowLevelInit,
|
|
269
|
+
get: lowLevelGetOne,
|
|
270
|
+
getAll: lowLevelGetAll,
|
|
271
|
+
has: lowLevelHas,
|
|
272
|
+
set: lowLevelSet,
|
|
273
|
+
remove: lowLevelRemove,
|
|
274
|
+
reset: lowLevelReset,
|
|
275
|
+
doMaintenance: lowLevelDoMaintenance,
|
|
276
|
+
setOptions: lowLevelSetOptions
|
|
366
277
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
LimitedCache,
|
|
387
|
-
LimitedCacheObject,
|
|
388
|
-
MAXIMUM_CACHE_TIME,
|
|
389
|
-
defaultOptions,
|
|
390
|
-
getCacheMetaFromObject,
|
|
391
|
-
isCacheMeta,
|
|
392
|
-
limitedCacheUtil,
|
|
393
|
-
lowLevelDoMaintenance,
|
|
394
|
-
lowLevelGetAll,
|
|
395
|
-
lowLevelGetOne,
|
|
396
|
-
lowLevelHas,
|
|
397
|
-
lowLevelInit,
|
|
398
|
-
lowLevelRemove,
|
|
399
|
-
lowLevelReset,
|
|
400
|
-
lowLevelSet,
|
|
401
|
-
lowLevelSetOptions,
|
|
402
|
-
upgradeCacheMeta
|
|
403
|
-
});
|
|
278
|
+
//#endregion
|
|
279
|
+
exports.CURRENT_META_VERSION = CURRENT_META_VERSION;
|
|
280
|
+
exports.LimitedCache = LimitedCache;
|
|
281
|
+
exports.LimitedCacheObject = LimitedCacheObject;
|
|
282
|
+
exports.MAXIMUM_CACHE_TIME = MAXIMUM_CACHE_TIME;
|
|
283
|
+
exports.defaultOptions = defaultOptions;
|
|
284
|
+
exports.getCacheMetaFromObject = getCacheMetaFromObject;
|
|
285
|
+
exports.isCacheMeta = isCacheMeta;
|
|
286
|
+
exports.limitedCacheUtil = limitedCacheUtil;
|
|
287
|
+
exports.lowLevelDoMaintenance = lowLevelDoMaintenance;
|
|
288
|
+
exports.lowLevelGetAll = lowLevelGetAll;
|
|
289
|
+
exports.lowLevelGetOne = lowLevelGetOne;
|
|
290
|
+
exports.lowLevelHas = lowLevelHas;
|
|
291
|
+
exports.lowLevelInit = lowLevelInit;
|
|
292
|
+
exports.lowLevelRemove = lowLevelRemove;
|
|
293
|
+
exports.lowLevelReset = lowLevelReset;
|
|
294
|
+
exports.lowLevelSet = lowLevelSet;
|
|
295
|
+
exports.lowLevelSetOptions = lowLevelSetOptions;
|
|
296
|
+
exports.upgradeCacheMeta = upgradeCacheMeta;
|