cacheable 1.10.4 → 2.0.1
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/README.md +58 -164
- package/dist/index.cjs +374 -1311
- package/dist/index.d.cts +106 -489
- package/dist/index.d.ts +106 -489
- package/dist/index.js +387 -1290
- package/package.json +14 -10
package/dist/index.js
CHANGED
|
@@ -1,1208 +1,23 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
throw new Error(`Unsupported hash algorithm: '${algorithm}'`);
|
|
20
|
-
}
|
|
21
|
-
const hasher = crypto.createHash(algorithm);
|
|
22
|
-
hasher.update(objectString);
|
|
23
|
-
const hashHex = hasher.digest("hex");
|
|
24
|
-
const hashNumber = Number.parseInt(hashHex, 16);
|
|
25
|
-
const range = max - min + 1;
|
|
26
|
-
return min + hashNumber % range;
|
|
27
|
-
}
|
|
28
|
-
function djb2Hash(string_, min = 0, max = 10) {
|
|
29
|
-
let hash2 = 5381;
|
|
30
|
-
for (let i = 0; i < string_.length; i++) {
|
|
31
|
-
hash2 = hash2 * 33 ^ string_.charCodeAt(i);
|
|
32
|
-
}
|
|
33
|
-
const range = max - min + 1;
|
|
34
|
-
return min + Math.abs(hash2) % range;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// src/keyv-memory.ts
|
|
38
|
-
import { Keyv } from "keyv";
|
|
39
|
-
|
|
40
|
-
// src/memory.ts
|
|
41
|
-
import { Hookified } from "hookified";
|
|
42
|
-
|
|
43
|
-
// src/memory-lru.ts
|
|
44
|
-
var ListNode = class {
|
|
45
|
-
value;
|
|
46
|
-
prev = void 0;
|
|
47
|
-
next = void 0;
|
|
48
|
-
constructor(value) {
|
|
49
|
-
this.value = value;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
var DoublyLinkedList = class {
|
|
53
|
-
head = void 0;
|
|
54
|
-
tail = void 0;
|
|
55
|
-
nodesMap = /* @__PURE__ */ new Map();
|
|
56
|
-
// Add a new node to the front (most recently used)
|
|
57
|
-
addToFront(value) {
|
|
58
|
-
const newNode = new ListNode(value);
|
|
59
|
-
if (this.head) {
|
|
60
|
-
newNode.next = this.head;
|
|
61
|
-
this.head.prev = newNode;
|
|
62
|
-
this.head = newNode;
|
|
63
|
-
} else {
|
|
64
|
-
this.head = this.tail = newNode;
|
|
65
|
-
}
|
|
66
|
-
this.nodesMap.set(value, newNode);
|
|
67
|
-
}
|
|
68
|
-
// Move an existing node to the front (most recently used)
|
|
69
|
-
moveToFront(value) {
|
|
70
|
-
const node = this.nodesMap.get(value);
|
|
71
|
-
if (!node || this.head === node) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
if (node.prev) {
|
|
75
|
-
node.prev.next = node.next;
|
|
76
|
-
}
|
|
77
|
-
if (node.next) {
|
|
78
|
-
node.next.prev = node.prev;
|
|
79
|
-
}
|
|
80
|
-
if (node === this.tail) {
|
|
81
|
-
this.tail = node.prev;
|
|
82
|
-
}
|
|
83
|
-
node.prev = void 0;
|
|
84
|
-
node.next = this.head;
|
|
85
|
-
if (this.head) {
|
|
86
|
-
this.head.prev = node;
|
|
87
|
-
}
|
|
88
|
-
this.head = node;
|
|
89
|
-
this.tail ??= node;
|
|
90
|
-
}
|
|
91
|
-
// Get the oldest node (tail)
|
|
92
|
-
getOldest() {
|
|
93
|
-
return this.tail ? this.tail.value : void 0;
|
|
94
|
-
}
|
|
95
|
-
// Remove the oldest node (tail)
|
|
96
|
-
removeOldest() {
|
|
97
|
-
if (!this.tail) {
|
|
98
|
-
return void 0;
|
|
99
|
-
}
|
|
100
|
-
const oldValue = this.tail.value;
|
|
101
|
-
if (this.tail.prev) {
|
|
102
|
-
this.tail = this.tail.prev;
|
|
103
|
-
this.tail.next = void 0;
|
|
104
|
-
} else {
|
|
105
|
-
this.head = this.tail = void 0;
|
|
106
|
-
}
|
|
107
|
-
this.nodesMap.delete(oldValue);
|
|
108
|
-
return oldValue;
|
|
109
|
-
}
|
|
110
|
-
get size() {
|
|
111
|
-
return this.nodesMap.size;
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// src/shorthand-time.ts
|
|
116
|
-
var shorthandToMilliseconds = (shorthand) => {
|
|
117
|
-
let milliseconds;
|
|
118
|
-
if (shorthand === void 0) {
|
|
119
|
-
return void 0;
|
|
120
|
-
}
|
|
121
|
-
if (typeof shorthand === "number") {
|
|
122
|
-
milliseconds = shorthand;
|
|
123
|
-
} else if (typeof shorthand === "string") {
|
|
124
|
-
shorthand = shorthand.trim();
|
|
125
|
-
if (Number.isNaN(Number(shorthand))) {
|
|
126
|
-
const match = /^([\d.]+)\s*(ms|s|m|h|hr|d)$/i.exec(shorthand);
|
|
127
|
-
if (!match) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
`Unsupported time format: "${shorthand}". Use 'ms', 's', 'm', 'h', 'hr', or 'd'.`
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
const [, value, unit] = match;
|
|
133
|
-
const numericValue = Number.parseFloat(value);
|
|
134
|
-
const unitLower = unit.toLowerCase();
|
|
135
|
-
switch (unitLower) {
|
|
136
|
-
case "ms": {
|
|
137
|
-
milliseconds = numericValue;
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
case "s": {
|
|
141
|
-
milliseconds = numericValue * 1e3;
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
case "m": {
|
|
145
|
-
milliseconds = numericValue * 1e3 * 60;
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
case "h": {
|
|
149
|
-
milliseconds = numericValue * 1e3 * 60 * 60;
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
case "hr": {
|
|
153
|
-
milliseconds = numericValue * 1e3 * 60 * 60;
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
case "d": {
|
|
157
|
-
milliseconds = numericValue * 1e3 * 60 * 60 * 24;
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
/* c8 ignore next 3 */
|
|
161
|
-
default: {
|
|
162
|
-
milliseconds = Number(shorthand);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
} else {
|
|
166
|
-
milliseconds = Number(shorthand);
|
|
167
|
-
}
|
|
168
|
-
} else {
|
|
169
|
-
throw new TypeError("Time must be a string or a number.");
|
|
170
|
-
}
|
|
171
|
-
return milliseconds;
|
|
172
|
-
};
|
|
173
|
-
var shorthandToTime = (shorthand, fromDate) => {
|
|
174
|
-
fromDate ??= /* @__PURE__ */ new Date();
|
|
175
|
-
const milliseconds = shorthandToMilliseconds(shorthand);
|
|
176
|
-
if (milliseconds === void 0) {
|
|
177
|
-
return fromDate.getTime();
|
|
178
|
-
}
|
|
179
|
-
return fromDate.getTime() + milliseconds;
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// src/coalesce-async.ts
|
|
183
|
-
var callbacks = /* @__PURE__ */ new Map();
|
|
184
|
-
function hasKey(key) {
|
|
185
|
-
return callbacks.has(key);
|
|
186
|
-
}
|
|
187
|
-
function addKey(key) {
|
|
188
|
-
callbacks.set(key, []);
|
|
189
|
-
}
|
|
190
|
-
function removeKey(key) {
|
|
191
|
-
callbacks.delete(key);
|
|
192
|
-
}
|
|
193
|
-
function addCallbackToKey(key, callback) {
|
|
194
|
-
const stash = getCallbacksByKey(key);
|
|
195
|
-
stash.push(callback);
|
|
196
|
-
callbacks.set(key, stash);
|
|
197
|
-
}
|
|
198
|
-
function getCallbacksByKey(key) {
|
|
199
|
-
return callbacks.get(key) ?? [];
|
|
200
|
-
}
|
|
201
|
-
async function enqueue(key) {
|
|
202
|
-
return new Promise((resolve, reject) => {
|
|
203
|
-
const callback = { resolve, reject };
|
|
204
|
-
addCallbackToKey(key, callback);
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
function dequeue(key) {
|
|
208
|
-
const stash = getCallbacksByKey(key);
|
|
209
|
-
removeKey(key);
|
|
210
|
-
return stash;
|
|
211
|
-
}
|
|
212
|
-
function coalesce(options) {
|
|
213
|
-
const { key, error, result } = options;
|
|
214
|
-
for (const callback of dequeue(key)) {
|
|
215
|
-
if (error) {
|
|
216
|
-
callback.reject(error);
|
|
217
|
-
} else {
|
|
218
|
-
callback.resolve(result);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
async function coalesceAsync(key, fnc) {
|
|
223
|
-
if (!hasKey(key)) {
|
|
224
|
-
addKey(key);
|
|
225
|
-
try {
|
|
226
|
-
const result = await Promise.resolve(fnc());
|
|
227
|
-
coalesce({ key, result });
|
|
228
|
-
return result;
|
|
229
|
-
} catch (error) {
|
|
230
|
-
coalesce({ key, error });
|
|
231
|
-
throw error;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return enqueue(key);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// src/wrap.ts
|
|
238
|
-
function wrapSync(function_, options) {
|
|
239
|
-
const { ttl, keyPrefix, cache } = options;
|
|
240
|
-
return (...arguments_) => {
|
|
241
|
-
let cacheKey = createWrapKey(function_, arguments_, keyPrefix);
|
|
242
|
-
if (options.createKey) {
|
|
243
|
-
cacheKey = options.createKey(function_, arguments_, options);
|
|
244
|
-
}
|
|
245
|
-
let value = cache.get(cacheKey);
|
|
246
|
-
if (value === void 0) {
|
|
247
|
-
try {
|
|
248
|
-
value = function_(...arguments_);
|
|
249
|
-
cache.set(cacheKey, value, ttl);
|
|
250
|
-
} catch (error) {
|
|
251
|
-
cache.emit("error", error);
|
|
252
|
-
if (options.cacheErrors) {
|
|
253
|
-
cache.set(cacheKey, error, ttl);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return value;
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
async function getOrSet(key, function_, options) {
|
|
261
|
-
const keyString = typeof key === "function" ? key(options) : key;
|
|
262
|
-
let value = await options.cache.get(keyString);
|
|
263
|
-
if (value === void 0) {
|
|
264
|
-
const cacheId = options.cacheId ?? "default";
|
|
265
|
-
const coalesceKey = `${cacheId}::${keyString}`;
|
|
266
|
-
value = await coalesceAsync(coalesceKey, async () => {
|
|
267
|
-
try {
|
|
268
|
-
const result = await function_();
|
|
269
|
-
await options.cache.set(keyString, result, options.ttl);
|
|
270
|
-
return result;
|
|
271
|
-
} catch (error) {
|
|
272
|
-
options.cache.emit("error", error);
|
|
273
|
-
if (options.cacheErrors) {
|
|
274
|
-
await options.cache.set(keyString, error, options.ttl);
|
|
275
|
-
}
|
|
276
|
-
if (options.throwErrors) {
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
return value;
|
|
283
|
-
}
|
|
284
|
-
function wrap(function_, options) {
|
|
285
|
-
const { keyPrefix, cache } = options;
|
|
286
|
-
return async (...arguments_) => {
|
|
287
|
-
let cacheKey = createWrapKey(function_, arguments_, keyPrefix);
|
|
288
|
-
if (options.createKey) {
|
|
289
|
-
cacheKey = options.createKey(function_, arguments_, options);
|
|
290
|
-
}
|
|
291
|
-
return cache.getOrSet(
|
|
292
|
-
cacheKey,
|
|
293
|
-
async () => function_(...arguments_),
|
|
294
|
-
options
|
|
295
|
-
);
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
function createWrapKey(function_, arguments_, keyPrefix) {
|
|
299
|
-
if (!keyPrefix) {
|
|
300
|
-
return `${function_.name}::${hash(arguments_)}`;
|
|
301
|
-
}
|
|
302
|
-
return `${keyPrefix}::${function_.name}::${hash(arguments_)}`;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// src/memory.ts
|
|
306
|
-
var defaultStoreHashSize = 16;
|
|
307
|
-
var maximumMapSize = 16777216;
|
|
308
|
-
var CacheableMemory = class extends Hookified {
|
|
309
|
-
_lru = new DoublyLinkedList();
|
|
310
|
-
_storeHashSize = defaultStoreHashSize;
|
|
311
|
-
_storeHashAlgorithm = "djb2Hash" /* djb2Hash */;
|
|
312
|
-
// Default is djb2Hash
|
|
313
|
-
_store = Array.from(
|
|
314
|
-
{ length: this._storeHashSize },
|
|
315
|
-
() => /* @__PURE__ */ new Map()
|
|
316
|
-
);
|
|
317
|
-
_ttl;
|
|
318
|
-
// Turned off by default
|
|
319
|
-
_useClone = true;
|
|
320
|
-
// Turned on by default
|
|
321
|
-
_lruSize = 0;
|
|
322
|
-
// Turned off by default
|
|
323
|
-
_checkInterval = 0;
|
|
324
|
-
// Turned off by default
|
|
325
|
-
_interval = 0;
|
|
326
|
-
// Turned off by default
|
|
327
|
-
/**
|
|
328
|
-
* @constructor
|
|
329
|
-
* @param {CacheableMemoryOptions} [options] - The options for the CacheableMemory
|
|
330
|
-
*/
|
|
331
|
-
constructor(options) {
|
|
332
|
-
super();
|
|
333
|
-
if (options?.ttl) {
|
|
334
|
-
this.setTtl(options.ttl);
|
|
335
|
-
}
|
|
336
|
-
if (options?.useClone !== void 0) {
|
|
337
|
-
this._useClone = options.useClone;
|
|
338
|
-
}
|
|
339
|
-
if (options?.storeHashSize && options.storeHashSize > 0) {
|
|
340
|
-
this._storeHashSize = options.storeHashSize;
|
|
341
|
-
}
|
|
342
|
-
if (options?.lruSize) {
|
|
343
|
-
if (options.lruSize > maximumMapSize) {
|
|
344
|
-
this.emit(
|
|
345
|
-
"error",
|
|
346
|
-
new Error(
|
|
347
|
-
`LRU size cannot be larger than ${maximumMapSize} due to Map limitations.`
|
|
348
|
-
)
|
|
349
|
-
);
|
|
350
|
-
} else {
|
|
351
|
-
this._lruSize = options.lruSize;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
if (options?.checkInterval) {
|
|
355
|
-
this._checkInterval = options.checkInterval;
|
|
356
|
-
}
|
|
357
|
-
if (options?.storeHashAlgorithm) {
|
|
358
|
-
this._storeHashAlgorithm = options.storeHashAlgorithm;
|
|
359
|
-
}
|
|
360
|
-
this._store = Array.from(
|
|
361
|
-
{ length: this._storeHashSize },
|
|
362
|
-
() => /* @__PURE__ */ new Map()
|
|
363
|
-
);
|
|
364
|
-
this.startIntervalCheck();
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Gets the time-to-live
|
|
368
|
-
* @returns {number|string|undefined} - The time-to-live in miliseconds or a human-readable format. If undefined, it will not have a time-to-live.
|
|
369
|
-
*/
|
|
370
|
-
get ttl() {
|
|
371
|
-
return this._ttl;
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Sets the time-to-live
|
|
375
|
-
* @param {number|string|undefined} value - The time-to-live in miliseconds or a human-readable format (example '1s' = 1 second, '1h' = 1 hour). If undefined, it will not have a time-to-live.
|
|
376
|
-
*/
|
|
377
|
-
set ttl(value) {
|
|
378
|
-
this.setTtl(value);
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Gets whether to use clone
|
|
382
|
-
* @returns {boolean} - If true, it will clone the value before returning it. If false, it will return the value directly. Default is true.
|
|
383
|
-
*/
|
|
384
|
-
get useClone() {
|
|
385
|
-
return this._useClone;
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Sets whether to use clone
|
|
389
|
-
* @param {boolean} value - If true, it will clone the value before returning it. If false, it will return the value directly. Default is true.
|
|
390
|
-
*/
|
|
391
|
-
set useClone(value) {
|
|
392
|
-
this._useClone = value;
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* Gets the size of the LRU cache
|
|
396
|
-
* @returns {number} - The size of the LRU cache. If set to 0, it will not use LRU cache. Default is 0. If you are using LRU then the limit is based on Map() size 17mm.
|
|
397
|
-
*/
|
|
398
|
-
get lruSize() {
|
|
399
|
-
return this._lruSize;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Sets the size of the LRU cache
|
|
403
|
-
* @param {number} value - The size of the LRU cache. If set to 0, it will not use LRU cache. Default is 0. If you are using LRU then the limit is based on Map() size 17mm.
|
|
404
|
-
*/
|
|
405
|
-
set lruSize(value) {
|
|
406
|
-
if (value > maximumMapSize) {
|
|
407
|
-
this.emit(
|
|
408
|
-
"error",
|
|
409
|
-
new Error(
|
|
410
|
-
`LRU size cannot be larger than ${maximumMapSize} due to Map limitations.`
|
|
411
|
-
)
|
|
412
|
-
);
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
this._lruSize = value;
|
|
416
|
-
if (this._lruSize === 0) {
|
|
417
|
-
this._lru = new DoublyLinkedList();
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
this.lruResize();
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Gets the check interval
|
|
424
|
-
* @returns {number} - The interval to check for expired items. If set to 0, it will not check for expired items. Default is 0.
|
|
425
|
-
*/
|
|
426
|
-
get checkInterval() {
|
|
427
|
-
return this._checkInterval;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Sets the check interval
|
|
431
|
-
* @param {number} value - The interval to check for expired items. If set to 0, it will not check for expired items. Default is 0.
|
|
432
|
-
*/
|
|
433
|
-
set checkInterval(value) {
|
|
434
|
-
this._checkInterval = value;
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Gets the size of the cache
|
|
438
|
-
* @returns {number} - The size of the cache
|
|
439
|
-
*/
|
|
440
|
-
get size() {
|
|
441
|
-
let size = 0;
|
|
442
|
-
for (const store of this._store) {
|
|
443
|
-
size += store.size;
|
|
444
|
-
}
|
|
445
|
-
return size;
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Gets the number of hash stores
|
|
449
|
-
* @returns {number} - The number of hash stores
|
|
450
|
-
*/
|
|
451
|
-
get storeHashSize() {
|
|
452
|
-
return this._storeHashSize;
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Sets the number of hash stores. This will recreate the store and all data will be cleared
|
|
456
|
-
* @param {number} value - The number of hash stores
|
|
457
|
-
*/
|
|
458
|
-
set storeHashSize(value) {
|
|
459
|
-
if (value === this._storeHashSize) {
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
this._storeHashSize = value;
|
|
463
|
-
this._store = Array.from(
|
|
464
|
-
{ length: this._storeHashSize },
|
|
465
|
-
() => /* @__PURE__ */ new Map()
|
|
466
|
-
);
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Gets the store hash algorithm
|
|
470
|
-
* @returns {StoreHashAlgorithm | StoreHashAlgorithmFunction} - The store hash algorithm
|
|
471
|
-
*/
|
|
472
|
-
get storeHashAlgorithm() {
|
|
473
|
-
return this._storeHashAlgorithm;
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Sets the store hash algorithm. This will recreate the store and all data will be cleared
|
|
477
|
-
* @param {StoreHashAlgorithm | StoreHashAlgorithmFunction} value - The store hash algorithm
|
|
478
|
-
*/
|
|
479
|
-
set storeHashAlgorithm(value) {
|
|
480
|
-
this._storeHashAlgorithm = value;
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Gets the keys
|
|
484
|
-
* @returns {IterableIterator<string>} - The keys
|
|
485
|
-
*/
|
|
486
|
-
get keys() {
|
|
487
|
-
const keys = [];
|
|
488
|
-
for (const store of this._store) {
|
|
489
|
-
for (const key of store.keys()) {
|
|
490
|
-
const item = store.get(key);
|
|
491
|
-
if (item && this.hasExpired(item)) {
|
|
492
|
-
store.delete(key);
|
|
493
|
-
continue;
|
|
494
|
-
}
|
|
495
|
-
keys.push(key);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
return keys.values();
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Gets the items
|
|
502
|
-
* @returns {IterableIterator<CacheableStoreItem>} - The items
|
|
503
|
-
*/
|
|
504
|
-
get items() {
|
|
505
|
-
const items = [];
|
|
506
|
-
for (const store of this._store) {
|
|
507
|
-
for (const item of store.values()) {
|
|
508
|
-
if (this.hasExpired(item)) {
|
|
509
|
-
store.delete(item.key);
|
|
510
|
-
continue;
|
|
511
|
-
}
|
|
512
|
-
items.push(item);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return items.values();
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Gets the store
|
|
519
|
-
* @returns {Array<Map<string, CacheableStoreItem>>} - The store
|
|
520
|
-
*/
|
|
521
|
-
get store() {
|
|
522
|
-
return this._store;
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Gets the value of the key
|
|
526
|
-
* @param {string} key - The key to get the value
|
|
527
|
-
* @returns {T | undefined} - The value of the key
|
|
528
|
-
*/
|
|
529
|
-
get(key) {
|
|
530
|
-
const store = this.getStore(key);
|
|
531
|
-
const item = store.get(key);
|
|
532
|
-
if (!item) {
|
|
533
|
-
return void 0;
|
|
534
|
-
}
|
|
535
|
-
if (item.expires && Date.now() > item.expires) {
|
|
536
|
-
store.delete(key);
|
|
537
|
-
return void 0;
|
|
538
|
-
}
|
|
539
|
-
this.lruMoveToFront(key);
|
|
540
|
-
if (!this._useClone) {
|
|
541
|
-
return item.value;
|
|
542
|
-
}
|
|
543
|
-
return this.clone(item.value);
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Gets the values of the keys
|
|
547
|
-
* @param {string[]} keys - The keys to get the values
|
|
548
|
-
* @returns {T[]} - The values of the keys
|
|
549
|
-
*/
|
|
550
|
-
getMany(keys) {
|
|
551
|
-
const result = [];
|
|
552
|
-
for (const key of keys) {
|
|
553
|
-
result.push(this.get(key));
|
|
554
|
-
}
|
|
555
|
-
return result;
|
|
556
|
-
}
|
|
557
|
-
/**
|
|
558
|
-
* Gets the raw value of the key
|
|
559
|
-
* @param {string} key - The key to get the value
|
|
560
|
-
* @returns {CacheableStoreItem | undefined} - The raw value of the key
|
|
561
|
-
*/
|
|
562
|
-
getRaw(key) {
|
|
563
|
-
const store = this.getStore(key);
|
|
564
|
-
const item = store.get(key);
|
|
565
|
-
if (!item) {
|
|
566
|
-
return void 0;
|
|
567
|
-
}
|
|
568
|
-
if (item.expires && item.expires && Date.now() > item.expires) {
|
|
569
|
-
store.delete(key);
|
|
570
|
-
return void 0;
|
|
571
|
-
}
|
|
572
|
-
this.lruMoveToFront(key);
|
|
573
|
-
return item;
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Gets the raw values of the keys
|
|
577
|
-
* @param {string[]} keys - The keys to get the values
|
|
578
|
-
* @returns {CacheableStoreItem[]} - The raw values of the keys
|
|
579
|
-
*/
|
|
580
|
-
getManyRaw(keys) {
|
|
581
|
-
const result = [];
|
|
582
|
-
for (const key of keys) {
|
|
583
|
-
result.push(this.getRaw(key));
|
|
584
|
-
}
|
|
585
|
-
return result;
|
|
586
|
-
}
|
|
587
|
-
/**
|
|
588
|
-
* Sets the value of the key
|
|
589
|
-
* @param {string} key - The key to set the value
|
|
590
|
-
* @param {any} value - The value to set
|
|
591
|
-
* @param {number|string|SetOptions} [ttl] - Time to Live - If you set a number it is miliseconds, if you set a string it is a human-readable.
|
|
592
|
-
* If you want to set expire directly you can do that by setting the expire property in the SetOptions.
|
|
593
|
-
* If you set undefined, it will use the default time-to-live. If both are undefined then it will not have a time-to-live.
|
|
594
|
-
* @returns {void}
|
|
595
|
-
*/
|
|
596
|
-
set(key, value, ttl) {
|
|
597
|
-
const store = this.getStore(key);
|
|
598
|
-
let expires;
|
|
599
|
-
if (ttl !== void 0 || this._ttl !== void 0) {
|
|
600
|
-
if (typeof ttl === "object") {
|
|
601
|
-
if (ttl.expire) {
|
|
602
|
-
expires = typeof ttl.expire === "number" ? ttl.expire : ttl.expire.getTime();
|
|
603
|
-
}
|
|
604
|
-
if (ttl.ttl) {
|
|
605
|
-
const finalTtl = shorthandToTime(ttl.ttl);
|
|
606
|
-
if (finalTtl !== void 0) {
|
|
607
|
-
expires = finalTtl;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
} else {
|
|
611
|
-
const finalTtl = shorthandToTime(ttl ?? this._ttl);
|
|
612
|
-
if (finalTtl !== void 0) {
|
|
613
|
-
expires = finalTtl;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
if (this._lruSize > 0) {
|
|
618
|
-
if (store.has(key)) {
|
|
619
|
-
this.lruMoveToFront(key);
|
|
620
|
-
} else {
|
|
621
|
-
this.lruAddToFront(key);
|
|
622
|
-
if (this._lru.size > this._lruSize) {
|
|
623
|
-
const oldestKey = this._lru.getOldest();
|
|
624
|
-
if (oldestKey) {
|
|
625
|
-
this._lru.removeOldest();
|
|
626
|
-
this.delete(oldestKey);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
const item = { key, value, expires };
|
|
632
|
-
store.set(key, item);
|
|
633
|
-
}
|
|
634
|
-
/**
|
|
635
|
-
* Sets the values of the keys
|
|
636
|
-
* @param {CacheableItem[]} items - The items to set
|
|
637
|
-
* @returns {void}
|
|
638
|
-
*/
|
|
639
|
-
setMany(items) {
|
|
640
|
-
for (const item of items) {
|
|
641
|
-
this.set(item.key, item.value, item.ttl);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Checks if the key exists
|
|
646
|
-
* @param {string} key - The key to check
|
|
647
|
-
* @returns {boolean} - If true, the key exists. If false, the key does not exist.
|
|
648
|
-
*/
|
|
649
|
-
has(key) {
|
|
650
|
-
const item = this.get(key);
|
|
651
|
-
return Boolean(item);
|
|
652
|
-
}
|
|
653
|
-
/**
|
|
654
|
-
* @function hasMany
|
|
655
|
-
* @param {string[]} keys - The keys to check
|
|
656
|
-
* @returns {boolean[]} - If true, the key exists. If false, the key does not exist.
|
|
657
|
-
*/
|
|
658
|
-
hasMany(keys) {
|
|
659
|
-
const result = [];
|
|
660
|
-
for (const key of keys) {
|
|
661
|
-
const item = this.get(key);
|
|
662
|
-
result.push(Boolean(item));
|
|
663
|
-
}
|
|
664
|
-
return result;
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* Take will get the key and delete the entry from cache
|
|
668
|
-
* @param {string} key - The key to take
|
|
669
|
-
* @returns {T | undefined} - The value of the key
|
|
670
|
-
*/
|
|
671
|
-
take(key) {
|
|
672
|
-
const item = this.get(key);
|
|
673
|
-
if (!item) {
|
|
674
|
-
return void 0;
|
|
675
|
-
}
|
|
676
|
-
this.delete(key);
|
|
677
|
-
return item;
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* TakeMany will get the keys and delete the entries from cache
|
|
681
|
-
* @param {string[]} keys - The keys to take
|
|
682
|
-
* @returns {T[]} - The values of the keys
|
|
683
|
-
*/
|
|
684
|
-
takeMany(keys) {
|
|
685
|
-
const result = [];
|
|
686
|
-
for (const key of keys) {
|
|
687
|
-
result.push(this.take(key));
|
|
688
|
-
}
|
|
689
|
-
return result;
|
|
690
|
-
}
|
|
691
|
-
/**
|
|
692
|
-
* Delete the key
|
|
693
|
-
* @param {string} key - The key to delete
|
|
694
|
-
* @returns {void}
|
|
695
|
-
*/
|
|
696
|
-
delete(key) {
|
|
697
|
-
const store = this.getStore(key);
|
|
698
|
-
store.delete(key);
|
|
699
|
-
}
|
|
700
|
-
/**
|
|
701
|
-
* Delete the keys
|
|
702
|
-
* @param {string[]} keys - The keys to delete
|
|
703
|
-
* @returns {void}
|
|
704
|
-
*/
|
|
705
|
-
deleteMany(keys) {
|
|
706
|
-
for (const key of keys) {
|
|
707
|
-
this.delete(key);
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Clear the cache
|
|
712
|
-
* @returns {void}
|
|
713
|
-
*/
|
|
714
|
-
clear() {
|
|
715
|
-
this._store = Array.from(
|
|
716
|
-
{ length: this._storeHashSize },
|
|
717
|
-
() => /* @__PURE__ */ new Map()
|
|
718
|
-
);
|
|
719
|
-
this._lru = new DoublyLinkedList();
|
|
720
|
-
}
|
|
721
|
-
/**
|
|
722
|
-
* Get the store based on the key (internal use)
|
|
723
|
-
* @param {string} key - The key to get the store
|
|
724
|
-
* @returns {CacheableHashStore} - The store
|
|
725
|
-
*/
|
|
726
|
-
getStore(key) {
|
|
727
|
-
const hash2 = this.getKeyStoreHash(key);
|
|
728
|
-
this._store[hash2] ||= /* @__PURE__ */ new Map();
|
|
729
|
-
return this._store[hash2];
|
|
730
|
-
}
|
|
731
|
-
/**
|
|
732
|
-
* Hash the key for which store to go to (internal use)
|
|
733
|
-
* @param {string} key - The key to hash
|
|
734
|
-
* Available algorithms are: SHA256, SHA1, MD5, and djb2Hash.
|
|
735
|
-
* @returns {number} - The hashed key as a number
|
|
736
|
-
*/
|
|
737
|
-
getKeyStoreHash(key) {
|
|
738
|
-
if (this._store.length === 1) {
|
|
739
|
-
return 0;
|
|
740
|
-
}
|
|
741
|
-
if (this._storeHashAlgorithm === "djb2Hash" /* djb2Hash */) {
|
|
742
|
-
return djb2Hash(key, 0, this._storeHashSize);
|
|
743
|
-
}
|
|
744
|
-
if (typeof this._storeHashAlgorithm === "function") {
|
|
745
|
-
return this._storeHashAlgorithm(key, this._storeHashSize);
|
|
746
|
-
}
|
|
747
|
-
return hashToNumber(key, 0, this._storeHashSize, this._storeHashAlgorithm);
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Clone the value. This is for internal use
|
|
751
|
-
* @param {any} value - The value to clone
|
|
752
|
-
* @returns {any} - The cloned value
|
|
753
|
-
*/
|
|
754
|
-
clone(value) {
|
|
755
|
-
if (this.isPrimitive(value)) {
|
|
756
|
-
return value;
|
|
757
|
-
}
|
|
758
|
-
return structuredClone(value);
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* Add to the front of the LRU cache. This is for internal use
|
|
762
|
-
* @param {string} key - The key to add to the front
|
|
763
|
-
* @returns {void}
|
|
764
|
-
*/
|
|
765
|
-
lruAddToFront(key) {
|
|
766
|
-
if (this._lruSize === 0) {
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
this._lru.addToFront(key);
|
|
770
|
-
}
|
|
771
|
-
/**
|
|
772
|
-
* Move to the front of the LRU cache. This is for internal use
|
|
773
|
-
* @param {string} key - The key to move to the front
|
|
774
|
-
* @returns {void}
|
|
775
|
-
*/
|
|
776
|
-
lruMoveToFront(key) {
|
|
777
|
-
if (this._lruSize === 0) {
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
this._lru.moveToFront(key);
|
|
781
|
-
}
|
|
782
|
-
/**
|
|
783
|
-
* Resize the LRU cache. This is for internal use.
|
|
784
|
-
* @returns {void}
|
|
785
|
-
*/
|
|
786
|
-
lruResize() {
|
|
787
|
-
while (this._lru.size > this._lruSize) {
|
|
788
|
-
const oldestKey = this._lru.getOldest();
|
|
789
|
-
if (oldestKey) {
|
|
790
|
-
this._lru.removeOldest();
|
|
791
|
-
this.delete(oldestKey);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
/**
|
|
796
|
-
* Check for expiration. This is for internal use
|
|
797
|
-
* @returns {void}
|
|
798
|
-
*/
|
|
799
|
-
checkExpiration() {
|
|
800
|
-
for (const store of this._store) {
|
|
801
|
-
for (const item of store.values()) {
|
|
802
|
-
if (item.expires && Date.now() > item.expires) {
|
|
803
|
-
store.delete(item.key);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
/**
|
|
809
|
-
* Start the interval check. This is for internal use
|
|
810
|
-
* @returns {void}
|
|
811
|
-
*/
|
|
812
|
-
startIntervalCheck() {
|
|
813
|
-
if (this._checkInterval > 0) {
|
|
814
|
-
if (this._interval) {
|
|
815
|
-
clearInterval(this._interval);
|
|
816
|
-
}
|
|
817
|
-
this._interval = setInterval(() => {
|
|
818
|
-
this.checkExpiration();
|
|
819
|
-
}, this._checkInterval).unref();
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* Stop the interval check. This is for internal use
|
|
824
|
-
* @returns {void}
|
|
825
|
-
*/
|
|
826
|
-
stopIntervalCheck() {
|
|
827
|
-
if (this._interval) {
|
|
828
|
-
clearInterval(this._interval);
|
|
829
|
-
}
|
|
830
|
-
this._interval = 0;
|
|
831
|
-
this._checkInterval = 0;
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Wrap the function for caching
|
|
835
|
-
* @param {Function} function_ - The function to wrap
|
|
836
|
-
* @param {Object} [options] - The options to wrap
|
|
837
|
-
* @returns {Function} - The wrapped function
|
|
838
|
-
*/
|
|
839
|
-
wrap(function_, options) {
|
|
840
|
-
const wrapOptions = {
|
|
841
|
-
ttl: options?.ttl ?? this._ttl,
|
|
842
|
-
keyPrefix: options?.keyPrefix,
|
|
843
|
-
cache: this
|
|
844
|
-
};
|
|
845
|
-
return wrapSync(function_, wrapOptions);
|
|
846
|
-
}
|
|
847
|
-
isPrimitive(value) {
|
|
848
|
-
const result = false;
|
|
849
|
-
if (value === null || value === void 0) {
|
|
850
|
-
return true;
|
|
851
|
-
}
|
|
852
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
853
|
-
return true;
|
|
854
|
-
}
|
|
855
|
-
return result;
|
|
856
|
-
}
|
|
857
|
-
setTtl(ttl) {
|
|
858
|
-
if (typeof ttl === "string" || ttl === void 0) {
|
|
859
|
-
this._ttl = ttl;
|
|
860
|
-
} else if (ttl > 0) {
|
|
861
|
-
this._ttl = ttl;
|
|
862
|
-
} else {
|
|
863
|
-
this._ttl = void 0;
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
hasExpired(item) {
|
|
867
|
-
if (item.expires && Date.now() > item.expires) {
|
|
868
|
-
return true;
|
|
869
|
-
}
|
|
870
|
-
return false;
|
|
871
|
-
}
|
|
872
|
-
};
|
|
873
|
-
|
|
874
|
-
// src/keyv-memory.ts
|
|
875
|
-
var KeyvCacheableMemory = class {
|
|
876
|
-
opts = {
|
|
877
|
-
ttl: 0,
|
|
878
|
-
useClone: true,
|
|
879
|
-
lruSize: 0,
|
|
880
|
-
checkInterval: 0
|
|
881
|
-
};
|
|
882
|
-
_defaultCache = new CacheableMemory();
|
|
883
|
-
_nCache = /* @__PURE__ */ new Map();
|
|
884
|
-
_namespace;
|
|
885
|
-
constructor(options) {
|
|
886
|
-
if (options) {
|
|
887
|
-
this.opts = options;
|
|
888
|
-
this._defaultCache = new CacheableMemory(options);
|
|
889
|
-
if (options.namespace) {
|
|
890
|
-
this._namespace = options.namespace;
|
|
891
|
-
this._nCache.set(this._namespace, new CacheableMemory(options));
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
get namespace() {
|
|
896
|
-
return this._namespace;
|
|
897
|
-
}
|
|
898
|
-
set namespace(value) {
|
|
899
|
-
this._namespace = value;
|
|
900
|
-
}
|
|
901
|
-
get store() {
|
|
902
|
-
return this.getStore(this._namespace);
|
|
903
|
-
}
|
|
904
|
-
async get(key) {
|
|
905
|
-
const result = this.getStore(this._namespace).get(key);
|
|
906
|
-
if (result) {
|
|
907
|
-
return result;
|
|
908
|
-
}
|
|
909
|
-
return void 0;
|
|
910
|
-
}
|
|
911
|
-
async getMany(keys) {
|
|
912
|
-
const result = this.getStore(this._namespace).getMany(keys);
|
|
913
|
-
return result;
|
|
914
|
-
}
|
|
915
|
-
async set(key, value, ttl) {
|
|
916
|
-
this.getStore(this._namespace).set(key, value, ttl);
|
|
917
|
-
}
|
|
918
|
-
async setMany(values) {
|
|
919
|
-
this.getStore(this._namespace).setMany(values);
|
|
920
|
-
}
|
|
921
|
-
async delete(key) {
|
|
922
|
-
this.getStore(this._namespace).delete(key);
|
|
923
|
-
return true;
|
|
924
|
-
}
|
|
925
|
-
async deleteMany(key) {
|
|
926
|
-
this.getStore(this._namespace).deleteMany(key);
|
|
927
|
-
return true;
|
|
928
|
-
}
|
|
929
|
-
async clear() {
|
|
930
|
-
this.getStore(this._namespace).clear();
|
|
931
|
-
}
|
|
932
|
-
async has(key) {
|
|
933
|
-
return this.getStore(this._namespace).has(key);
|
|
934
|
-
}
|
|
935
|
-
on(event, listener) {
|
|
936
|
-
this.getStore(this._namespace).on(event, listener);
|
|
937
|
-
return this;
|
|
938
|
-
}
|
|
939
|
-
getStore(namespace) {
|
|
940
|
-
if (!namespace) {
|
|
941
|
-
return this._defaultCache;
|
|
942
|
-
}
|
|
943
|
-
if (!this._nCache.has(namespace)) {
|
|
944
|
-
this._nCache.set(namespace, new CacheableMemory(this.opts));
|
|
945
|
-
}
|
|
946
|
-
return this._nCache.get(namespace);
|
|
947
|
-
}
|
|
948
|
-
};
|
|
949
|
-
function createKeyv(options) {
|
|
950
|
-
const store = new KeyvCacheableMemory(options);
|
|
951
|
-
const namespace = options?.namespace;
|
|
952
|
-
let ttl;
|
|
953
|
-
if (options?.ttl && Number.isInteger(options.ttl)) {
|
|
954
|
-
ttl = options?.ttl;
|
|
955
|
-
}
|
|
956
|
-
const keyv = new Keyv({ store, namespace, ttl });
|
|
957
|
-
keyv.serialize = void 0;
|
|
958
|
-
keyv.deserialize = void 0;
|
|
959
|
-
return keyv;
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
// src/stats.ts
|
|
963
|
-
var CacheableStats = class {
|
|
964
|
-
_hits = 0;
|
|
965
|
-
_misses = 0;
|
|
966
|
-
_gets = 0;
|
|
967
|
-
_sets = 0;
|
|
968
|
-
_deletes = 0;
|
|
969
|
-
_clears = 0;
|
|
970
|
-
_vsize = 0;
|
|
971
|
-
_ksize = 0;
|
|
972
|
-
_count = 0;
|
|
973
|
-
_enabled = false;
|
|
974
|
-
constructor(options) {
|
|
975
|
-
if (options?.enabled) {
|
|
976
|
-
this._enabled = options.enabled;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
/**
|
|
980
|
-
* @returns {boolean} - Whether the stats are enabled
|
|
981
|
-
*/
|
|
982
|
-
get enabled() {
|
|
983
|
-
return this._enabled;
|
|
984
|
-
}
|
|
985
|
-
/**
|
|
986
|
-
* @param {boolean} enabled - Whether to enable the stats
|
|
987
|
-
*/
|
|
988
|
-
set enabled(enabled) {
|
|
989
|
-
this._enabled = enabled;
|
|
990
|
-
}
|
|
991
|
-
/**
|
|
992
|
-
* @returns {number} - The number of hits
|
|
993
|
-
* @readonly
|
|
994
|
-
*/
|
|
995
|
-
get hits() {
|
|
996
|
-
return this._hits;
|
|
997
|
-
}
|
|
998
|
-
/**
|
|
999
|
-
* @returns {number} - The number of misses
|
|
1000
|
-
* @readonly
|
|
1001
|
-
*/
|
|
1002
|
-
get misses() {
|
|
1003
|
-
return this._misses;
|
|
1004
|
-
}
|
|
1005
|
-
/**
|
|
1006
|
-
* @returns {number} - The number of gets
|
|
1007
|
-
* @readonly
|
|
1008
|
-
*/
|
|
1009
|
-
get gets() {
|
|
1010
|
-
return this._gets;
|
|
1011
|
-
}
|
|
1012
|
-
/**
|
|
1013
|
-
* @returns {number} - The number of sets
|
|
1014
|
-
* @readonly
|
|
1015
|
-
*/
|
|
1016
|
-
get sets() {
|
|
1017
|
-
return this._sets;
|
|
1018
|
-
}
|
|
1019
|
-
/**
|
|
1020
|
-
* @returns {number} - The number of deletes
|
|
1021
|
-
* @readonly
|
|
1022
|
-
*/
|
|
1023
|
-
get deletes() {
|
|
1024
|
-
return this._deletes;
|
|
1025
|
-
}
|
|
1026
|
-
/**
|
|
1027
|
-
* @returns {number} - The number of clears
|
|
1028
|
-
* @readonly
|
|
1029
|
-
*/
|
|
1030
|
-
get clears() {
|
|
1031
|
-
return this._clears;
|
|
1032
|
-
}
|
|
1033
|
-
/**
|
|
1034
|
-
* @returns {number} - The vsize (value size) of the cache instance
|
|
1035
|
-
* @readonly
|
|
1036
|
-
*/
|
|
1037
|
-
get vsize() {
|
|
1038
|
-
return this._vsize;
|
|
1039
|
-
}
|
|
1040
|
-
/**
|
|
1041
|
-
* @returns {number} - The ksize (key size) of the cache instance
|
|
1042
|
-
* @readonly
|
|
1043
|
-
*/
|
|
1044
|
-
get ksize() {
|
|
1045
|
-
return this._ksize;
|
|
1046
|
-
}
|
|
1047
|
-
/**
|
|
1048
|
-
* @returns {number} - The count of the cache instance
|
|
1049
|
-
* @readonly
|
|
1050
|
-
*/
|
|
1051
|
-
get count() {
|
|
1052
|
-
return this._count;
|
|
1053
|
-
}
|
|
1054
|
-
incrementHits() {
|
|
1055
|
-
if (!this._enabled) {
|
|
1056
|
-
return;
|
|
1057
|
-
}
|
|
1058
|
-
this._hits++;
|
|
1059
|
-
}
|
|
1060
|
-
incrementMisses() {
|
|
1061
|
-
if (!this._enabled) {
|
|
1062
|
-
return;
|
|
1063
|
-
}
|
|
1064
|
-
this._misses++;
|
|
1065
|
-
}
|
|
1066
|
-
incrementGets() {
|
|
1067
|
-
if (!this._enabled) {
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
this._gets++;
|
|
1071
|
-
}
|
|
1072
|
-
incrementSets() {
|
|
1073
|
-
if (!this._enabled) {
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
this._sets++;
|
|
1077
|
-
}
|
|
1078
|
-
incrementDeletes() {
|
|
1079
|
-
if (!this._enabled) {
|
|
1080
|
-
return;
|
|
1081
|
-
}
|
|
1082
|
-
this._deletes++;
|
|
1083
|
-
}
|
|
1084
|
-
incrementClears() {
|
|
1085
|
-
if (!this._enabled) {
|
|
1086
|
-
return;
|
|
1087
|
-
}
|
|
1088
|
-
this._clears++;
|
|
1089
|
-
}
|
|
1090
|
-
incrementVSize(value) {
|
|
1091
|
-
if (!this._enabled) {
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
|
-
this._vsize += this.roughSizeOfObject(value);
|
|
1095
|
-
}
|
|
1096
|
-
decreaseVSize(value) {
|
|
1097
|
-
if (!this._enabled) {
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
|
-
this._vsize -= this.roughSizeOfObject(value);
|
|
1101
|
-
}
|
|
1102
|
-
incrementKSize(key) {
|
|
1103
|
-
if (!this._enabled) {
|
|
1104
|
-
return;
|
|
1105
|
-
}
|
|
1106
|
-
this._ksize += this.roughSizeOfString(key);
|
|
1107
|
-
}
|
|
1108
|
-
decreaseKSize(key) {
|
|
1109
|
-
if (!this._enabled) {
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
|
-
this._ksize -= this.roughSizeOfString(key);
|
|
1113
|
-
}
|
|
1114
|
-
incrementCount() {
|
|
1115
|
-
if (!this._enabled) {
|
|
1116
|
-
return;
|
|
1117
|
-
}
|
|
1118
|
-
this._count++;
|
|
1119
|
-
}
|
|
1120
|
-
decreaseCount() {
|
|
1121
|
-
if (!this._enabled) {
|
|
1122
|
-
return;
|
|
1123
|
-
}
|
|
1124
|
-
this._count--;
|
|
1125
|
-
}
|
|
1126
|
-
setCount(count) {
|
|
1127
|
-
if (!this._enabled) {
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
this._count = count;
|
|
1131
|
-
}
|
|
1132
|
-
roughSizeOfString(value) {
|
|
1133
|
-
return value.length * 2;
|
|
1134
|
-
}
|
|
1135
|
-
roughSizeOfObject(object) {
|
|
1136
|
-
const objectList = [];
|
|
1137
|
-
const stack = [object];
|
|
1138
|
-
let bytes = 0;
|
|
1139
|
-
while (stack.length > 0) {
|
|
1140
|
-
const value = stack.pop();
|
|
1141
|
-
if (typeof value === "boolean") {
|
|
1142
|
-
bytes += 4;
|
|
1143
|
-
} else if (typeof value === "string") {
|
|
1144
|
-
bytes += value.length * 2;
|
|
1145
|
-
} else if (typeof value === "number") {
|
|
1146
|
-
bytes += 8;
|
|
1147
|
-
} else if (typeof value === "object" && value !== null && !objectList.includes(value)) {
|
|
1148
|
-
objectList.push(value);
|
|
1149
|
-
for (const key in value) {
|
|
1150
|
-
bytes += key.length * 2;
|
|
1151
|
-
stack.push(value[key]);
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
return bytes;
|
|
1156
|
-
}
|
|
1157
|
-
reset() {
|
|
1158
|
-
this._hits = 0;
|
|
1159
|
-
this._misses = 0;
|
|
1160
|
-
this._gets = 0;
|
|
1161
|
-
this._sets = 0;
|
|
1162
|
-
this._deletes = 0;
|
|
1163
|
-
this._clears = 0;
|
|
1164
|
-
this._vsize = 0;
|
|
1165
|
-
this._ksize = 0;
|
|
1166
|
-
this._count = 0;
|
|
1167
|
-
}
|
|
1168
|
-
resetStoreValues() {
|
|
1169
|
-
this._vsize = 0;
|
|
1170
|
-
this._ksize = 0;
|
|
1171
|
-
this._count = 0;
|
|
1172
|
-
}
|
|
1173
|
-
};
|
|
1174
|
-
|
|
1175
|
-
// src/ttl.ts
|
|
1176
|
-
function getTtlFromExpires(expires) {
|
|
1177
|
-
if (expires === void 0 || expires === null) {
|
|
1178
|
-
return void 0;
|
|
1179
|
-
}
|
|
1180
|
-
const now = Date.now();
|
|
1181
|
-
if (expires < now) {
|
|
1182
|
-
return void 0;
|
|
1183
|
-
}
|
|
1184
|
-
return expires - now;
|
|
1185
|
-
}
|
|
1186
|
-
function getCascadingTtl(cacheableTtl, primaryTtl, secondaryTtl) {
|
|
1187
|
-
return secondaryTtl ?? primaryTtl ?? shorthandToMilliseconds(cacheableTtl);
|
|
1188
|
-
}
|
|
1189
|
-
function calculateTtlFromExpiration(ttl, expires) {
|
|
1190
|
-
const ttlFromExpires = getTtlFromExpires(expires);
|
|
1191
|
-
const expiresFromTtl = ttl ? Date.now() + ttl : void 0;
|
|
1192
|
-
if (ttlFromExpires === void 0) {
|
|
1193
|
-
return ttl;
|
|
1194
|
-
}
|
|
1195
|
-
if (expiresFromTtl === void 0) {
|
|
1196
|
-
return ttlFromExpires;
|
|
1197
|
-
}
|
|
1198
|
-
if (expires > expiresFromTtl) {
|
|
1199
|
-
return ttl;
|
|
1200
|
-
}
|
|
1201
|
-
return ttlFromExpires;
|
|
1202
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
getOrSet,
|
|
4
|
+
wrap
|
|
5
|
+
} from "@cacheable/memoize";
|
|
6
|
+
import { createKeyv } from "@cacheable/memory";
|
|
7
|
+
import {
|
|
8
|
+
Stats as CacheableStats,
|
|
9
|
+
calculateTtlFromExpiration,
|
|
10
|
+
getCascadingTtl,
|
|
11
|
+
HashAlgorithm,
|
|
12
|
+
hash,
|
|
13
|
+
shorthandToMilliseconds
|
|
14
|
+
} from "@cacheable/utils";
|
|
15
|
+
import { Hookified } from "hookified";
|
|
16
|
+
import {
|
|
17
|
+
Keyv
|
|
18
|
+
} from "keyv";
|
|
1203
19
|
|
|
1204
|
-
// src/
|
|
1205
|
-
import { Keyv as Keyv3, KeyvHooks } from "keyv";
|
|
20
|
+
// src/enums.ts
|
|
1206
21
|
var CacheableHooks = /* @__PURE__ */ ((CacheableHooks2) => {
|
|
1207
22
|
CacheableHooks2["BEFORE_SET"] = "BEFORE_SET";
|
|
1208
23
|
CacheableHooks2["AFTER_SET"] = "AFTER_SET";
|
|
@@ -1217,9 +32,33 @@ var CacheableHooks = /* @__PURE__ */ ((CacheableHooks2) => {
|
|
|
1217
32
|
})(CacheableHooks || {});
|
|
1218
33
|
var CacheableEvents = /* @__PURE__ */ ((CacheableEvents2) => {
|
|
1219
34
|
CacheableEvents2["ERROR"] = "error";
|
|
35
|
+
CacheableEvents2["CACHE_HIT"] = "cache:hit";
|
|
36
|
+
CacheableEvents2["CACHE_MISS"] = "cache:miss";
|
|
1220
37
|
return CacheableEvents2;
|
|
1221
38
|
})(CacheableEvents || {});
|
|
1222
|
-
|
|
39
|
+
|
|
40
|
+
// src/index.ts
|
|
41
|
+
import {
|
|
42
|
+
getOrSet as getOrSet2,
|
|
43
|
+
wrap as wrap2,
|
|
44
|
+
wrapSync
|
|
45
|
+
} from "@cacheable/memoize";
|
|
46
|
+
import {
|
|
47
|
+
CacheableMemory,
|
|
48
|
+
createKeyv as createKeyv2,
|
|
49
|
+
KeyvCacheableMemory
|
|
50
|
+
} from "@cacheable/memory";
|
|
51
|
+
import {
|
|
52
|
+
calculateTtlFromExpiration as calculateTtlFromExpiration2,
|
|
53
|
+
getCascadingTtl as getCascadingTtl2,
|
|
54
|
+
HashAlgorithm as HashAlgorithm2,
|
|
55
|
+
hash as hash2,
|
|
56
|
+
Stats,
|
|
57
|
+
shorthandToMilliseconds as shorthandToMilliseconds2,
|
|
58
|
+
shorthandToTime
|
|
59
|
+
} from "@cacheable/utils";
|
|
60
|
+
import { Keyv as Keyv2, KeyvHooks } from "keyv";
|
|
61
|
+
var Cacheable = class extends Hookified {
|
|
1223
62
|
_primary = createKeyv();
|
|
1224
63
|
_secondary;
|
|
1225
64
|
_nonBlocking = false;
|
|
@@ -1402,7 +241,7 @@ var Cacheable = class extends Hookified2 {
|
|
|
1402
241
|
if (this.isKeyvInstance(primary)) {
|
|
1403
242
|
this._primary = primary;
|
|
1404
243
|
} else {
|
|
1405
|
-
this._primary = new
|
|
244
|
+
this._primary = new Keyv(primary);
|
|
1406
245
|
}
|
|
1407
246
|
this._primary.on("error", (error) => {
|
|
1408
247
|
this.emit("error" /* ERROR */, error);
|
|
@@ -1417,7 +256,7 @@ var Cacheable = class extends Hookified2 {
|
|
|
1417
256
|
if (this.isKeyvInstance(secondary)) {
|
|
1418
257
|
this._secondary = secondary;
|
|
1419
258
|
} else {
|
|
1420
|
-
this._secondary = new
|
|
259
|
+
this._secondary = new Keyv(secondary);
|
|
1421
260
|
}
|
|
1422
261
|
this._secondary.on("error", (error) => {
|
|
1423
262
|
this.emit("error" /* ERROR */, error);
|
|
@@ -1425,7 +264,7 @@ var Cacheable = class extends Hookified2 {
|
|
|
1425
264
|
}
|
|
1426
265
|
// biome-ignore lint/suspicious/noExplicitAny: type format
|
|
1427
266
|
isKeyvInstance(keyv) {
|
|
1428
|
-
if (keyv instanceof
|
|
267
|
+
if (keyv instanceof Keyv) {
|
|
1429
268
|
return true;
|
|
1430
269
|
}
|
|
1431
270
|
const keyvMethods = [
|
|
@@ -1451,26 +290,68 @@ var Cacheable = class extends Hookified2 {
|
|
|
1451
290
|
}
|
|
1452
291
|
return this._namespace;
|
|
1453
292
|
}
|
|
1454
|
-
|
|
293
|
+
/**
|
|
294
|
+
* Retrieves an entry from the cache.
|
|
295
|
+
*
|
|
296
|
+
* Checks the primary store first; if not found and a secondary store is configured,
|
|
297
|
+
* it will fetch from the secondary, repopulate the primary, and return the result.
|
|
298
|
+
*
|
|
299
|
+
* @typeParam T - The expected type of the stored value.
|
|
300
|
+
* @param {string} key - The cache key to retrieve.
|
|
301
|
+
* @param {GetOptions} - options such as to bypass `nonBlocking` for this call
|
|
302
|
+
* @returns {Promise<T | undefined>}
|
|
303
|
+
* A promise that resolves to the cached value if found, or `undefined`.
|
|
304
|
+
*/
|
|
305
|
+
async get(key, options) {
|
|
306
|
+
const result = await this.getRaw(key, options);
|
|
307
|
+
return result?.value;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Retrieves the raw entry from the cache including metadata like expiration.
|
|
311
|
+
*
|
|
312
|
+
* Checks the primary store first; if not found and a secondary store is configured,
|
|
313
|
+
* it will fetch from the secondary, repopulate the primary, and return the result.
|
|
314
|
+
*
|
|
315
|
+
* @typeParam T - The expected type of the stored value.
|
|
316
|
+
* @param {string} key - The cache key to retrieve.
|
|
317
|
+
* @param {GetOptions} - options such as to bypass `nonBlocking` for this call
|
|
318
|
+
* @returns {Promise<StoredDataRaw<T>>}
|
|
319
|
+
* A promise that resolves to the full raw data object if found, or undefined.
|
|
320
|
+
*/
|
|
321
|
+
async getRaw(key, options) {
|
|
1455
322
|
let result;
|
|
1456
|
-
const { raw = false } = options;
|
|
1457
323
|
try {
|
|
1458
324
|
await this.hook("BEFORE_GET" /* BEFORE_GET */, key);
|
|
1459
|
-
result = await this._primary.
|
|
325
|
+
result = await this._primary.getRaw(key);
|
|
1460
326
|
let ttl;
|
|
327
|
+
if (result) {
|
|
328
|
+
this.emit("cache:hit" /* CACHE_HIT */, {
|
|
329
|
+
key,
|
|
330
|
+
value: result.value,
|
|
331
|
+
store: "primary"
|
|
332
|
+
});
|
|
333
|
+
} else {
|
|
334
|
+
this.emit("cache:miss" /* CACHE_MISS */, { key, store: "primary" });
|
|
335
|
+
}
|
|
336
|
+
const nonBlocking = options?.nonBlocking ?? this._nonBlocking;
|
|
1461
337
|
if (!result && this._secondary) {
|
|
1462
|
-
|
|
1463
|
-
if (
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
338
|
+
let secondaryProcessResult;
|
|
339
|
+
if (nonBlocking) {
|
|
340
|
+
secondaryProcessResult = await this.processSecondaryForGetRawNonBlocking(
|
|
341
|
+
this._primary,
|
|
342
|
+
this._secondary,
|
|
343
|
+
key
|
|
344
|
+
);
|
|
345
|
+
} else {
|
|
346
|
+
secondaryProcessResult = await this.processSecondaryForGetRaw(
|
|
347
|
+
this._primary,
|
|
348
|
+
this._secondary,
|
|
349
|
+
key
|
|
1472
350
|
);
|
|
1473
|
-
|
|
351
|
+
}
|
|
352
|
+
if (secondaryProcessResult) {
|
|
353
|
+
result = secondaryProcessResult.result;
|
|
354
|
+
ttl = secondaryProcessResult.ttl;
|
|
1474
355
|
}
|
|
1475
356
|
}
|
|
1476
357
|
await this.hook("AFTER_GET" /* AFTER_GET */, { key, result, ttl });
|
|
@@ -1485,38 +366,52 @@ var Cacheable = class extends Hookified2 {
|
|
|
1485
366
|
}
|
|
1486
367
|
this.stats.incrementGets();
|
|
1487
368
|
}
|
|
1488
|
-
return
|
|
369
|
+
return result;
|
|
1489
370
|
}
|
|
1490
|
-
|
|
371
|
+
/**
|
|
372
|
+
* Retrieves multiple raw entries from the cache including metadata like expiration.
|
|
373
|
+
*
|
|
374
|
+
* Checks the primary store for each key; if a key is missing and a secondary store is configured,
|
|
375
|
+
* it will fetch from the secondary store, repopulate the primary store, and return the results.
|
|
376
|
+
*
|
|
377
|
+
* @typeParam T - The expected type of the stored values.
|
|
378
|
+
* @param {string[]} keys - The cache keys to retrieve.
|
|
379
|
+
* @param {GetOptions} - options such as to bypass `nonBlocking` on this call
|
|
380
|
+
* @returns {Promise<Array<StoredDataRaw<T>>>}
|
|
381
|
+
* A promise that resolves to an array of raw data objects.
|
|
382
|
+
*/
|
|
383
|
+
async getManyRaw(keys, options) {
|
|
1491
384
|
let result = [];
|
|
1492
|
-
const { raw = false } = options;
|
|
1493
385
|
try {
|
|
1494
386
|
await this.hook("BEFORE_GET_MANY" /* BEFORE_GET_MANY */, keys);
|
|
1495
|
-
result = await this._primary.
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
387
|
+
result = await this._primary.getManyRaw(keys);
|
|
388
|
+
for (const [i, key] of keys.entries()) {
|
|
389
|
+
if (result[i]) {
|
|
390
|
+
this.emit("cache:hit" /* CACHE_HIT */, {
|
|
391
|
+
key,
|
|
392
|
+
value: result[i].value,
|
|
393
|
+
store: "primary"
|
|
394
|
+
});
|
|
395
|
+
} else {
|
|
396
|
+
this.emit("cache:miss" /* CACHE_MISS */, { key, store: "primary" });
|
|
1502
397
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
398
|
+
}
|
|
399
|
+
const nonBlocking = options?.nonBlocking ?? this._nonBlocking;
|
|
400
|
+
if (this._secondary) {
|
|
401
|
+
if (nonBlocking) {
|
|
402
|
+
await this.processSecondaryForGetManyRawNonBlocking(
|
|
403
|
+
this._primary,
|
|
404
|
+
this._secondary,
|
|
405
|
+
keys,
|
|
406
|
+
result
|
|
407
|
+
);
|
|
408
|
+
} else {
|
|
409
|
+
await this.processSecondaryForGetManyRaw(
|
|
410
|
+
this._primary,
|
|
411
|
+
this._secondary,
|
|
412
|
+
keys,
|
|
413
|
+
result
|
|
414
|
+
);
|
|
1520
415
|
}
|
|
1521
416
|
}
|
|
1522
417
|
await this.hook("AFTER_GET_MANY" /* AFTER_GET_MANY */, { keys, result });
|
|
@@ -1533,7 +428,22 @@ var Cacheable = class extends Hookified2 {
|
|
|
1533
428
|
}
|
|
1534
429
|
this.stats.incrementGets();
|
|
1535
430
|
}
|
|
1536
|
-
return
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Retrieves multiple entries from the cache.
|
|
435
|
+
* Checks the primary store for each key; if a key is missing and a secondary store is configured,
|
|
436
|
+
* it will fetch from the secondary store, repopulate the primary store, and return the results.
|
|
437
|
+
*
|
|
438
|
+
* @typeParam T - The expected type of the stored values.
|
|
439
|
+
* @param {string[]} keys - The cache keys to retrieve.
|
|
440
|
+
* @param {GetOptions} - options such as to bypass `nonBlocking` on this call
|
|
441
|
+
* @returns {Promise<Array<T | undefined>>}
|
|
442
|
+
* A promise that resolves to an array of cached values or `undefined` for misses.
|
|
443
|
+
*/
|
|
444
|
+
async getMany(keys, options) {
|
|
445
|
+
const result = await this.getManyRaw(keys, options);
|
|
446
|
+
return result.map((item) => item?.value);
|
|
1537
447
|
}
|
|
1538
448
|
/**
|
|
1539
449
|
* Sets the value of the key. If the secondary store is set then it will also set the value in the secondary store.
|
|
@@ -1556,6 +466,11 @@ var Cacheable = class extends Hookified2 {
|
|
|
1556
466
|
}
|
|
1557
467
|
if (this._nonBlocking) {
|
|
1558
468
|
result = await Promise.race(promises);
|
|
469
|
+
for (const promise of promises) {
|
|
470
|
+
promise.catch((error) => {
|
|
471
|
+
this.emit("error" /* ERROR */, error);
|
|
472
|
+
});
|
|
473
|
+
}
|
|
1559
474
|
} else {
|
|
1560
475
|
const results = await Promise.all(promises);
|
|
1561
476
|
result = results[0];
|
|
@@ -1584,7 +499,9 @@ var Cacheable = class extends Hookified2 {
|
|
|
1584
499
|
result = await this.setManyKeyv(this._primary, items);
|
|
1585
500
|
if (this._secondary) {
|
|
1586
501
|
if (this._nonBlocking) {
|
|
1587
|
-
this.setManyKeyv(this._secondary, items)
|
|
502
|
+
this.setManyKeyv(this._secondary, items).catch((error) => {
|
|
503
|
+
this.emit("error" /* ERROR */, error);
|
|
504
|
+
});
|
|
1588
505
|
} else {
|
|
1589
506
|
await this.setManyKeyv(this._secondary, items);
|
|
1590
507
|
}
|
|
@@ -1687,6 +604,11 @@ var Cacheable = class extends Hookified2 {
|
|
|
1687
604
|
}
|
|
1688
605
|
if (this.nonBlocking) {
|
|
1689
606
|
result = await Promise.race(promises);
|
|
607
|
+
for (const promise of promises) {
|
|
608
|
+
promise.catch((error) => {
|
|
609
|
+
this.emit("error" /* ERROR */, error);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
1690
612
|
} else {
|
|
1691
613
|
const resultAll = await Promise.all(promises);
|
|
1692
614
|
result = resultAll[0];
|
|
@@ -1708,12 +630,14 @@ var Cacheable = class extends Hookified2 {
|
|
|
1708
630
|
this.stats.incrementDeletes();
|
|
1709
631
|
}
|
|
1710
632
|
}
|
|
1711
|
-
const result = await this.
|
|
633
|
+
const result = await this._primary.deleteMany(keys);
|
|
1712
634
|
if (this._secondary) {
|
|
1713
635
|
if (this._nonBlocking) {
|
|
1714
|
-
this.
|
|
636
|
+
this._secondary.deleteMany(keys).catch((error) => {
|
|
637
|
+
this.emit("error" /* ERROR */, error);
|
|
638
|
+
});
|
|
1715
639
|
} else {
|
|
1716
|
-
await this.
|
|
640
|
+
await this._secondary.deleteMany(keys);
|
|
1717
641
|
}
|
|
1718
642
|
}
|
|
1719
643
|
return result;
|
|
@@ -1756,11 +680,30 @@ var Cacheable = class extends Hookified2 {
|
|
|
1756
680
|
*/
|
|
1757
681
|
// biome-ignore lint/suspicious/noExplicitAny: type format
|
|
1758
682
|
wrap(function_, options) {
|
|
683
|
+
const cacheAdapter = {
|
|
684
|
+
get: async (key) => this.get(key),
|
|
685
|
+
has: async (key) => this.has(key),
|
|
686
|
+
// biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
|
|
687
|
+
set: async (key, value, ttl) => {
|
|
688
|
+
await this.set(key, value, ttl);
|
|
689
|
+
},
|
|
690
|
+
/* c8 ignore start */
|
|
691
|
+
// biome-ignore lint/suspicious/noExplicitAny: CacheInstance interface
|
|
692
|
+
on: (event, listener) => {
|
|
693
|
+
this.on(event, listener);
|
|
694
|
+
},
|
|
695
|
+
/* c8 ignore stop */
|
|
696
|
+
// biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
|
|
697
|
+
emit: (event, ...args) => this.emit(event, ...args)
|
|
698
|
+
};
|
|
1759
699
|
const wrapOptions = {
|
|
1760
700
|
ttl: options?.ttl ?? this._ttl,
|
|
1761
701
|
keyPrefix: options?.keyPrefix,
|
|
1762
|
-
|
|
1763
|
-
|
|
702
|
+
createKey: options?.createKey,
|
|
703
|
+
cacheErrors: options?.cacheErrors,
|
|
704
|
+
cache: cacheAdapter,
|
|
705
|
+
cacheId: this._cacheId,
|
|
706
|
+
serialize: options?.serialize
|
|
1764
707
|
};
|
|
1765
708
|
return wrap(function_, wrapOptions);
|
|
1766
709
|
}
|
|
@@ -1775,8 +718,24 @@ var Cacheable = class extends Hookified2 {
|
|
|
1775
718
|
* @return {Promise<T | undefined>} - A promise that resolves to the cached or newly computed value, or undefined if an error occurs and caching is not configured for errors.
|
|
1776
719
|
*/
|
|
1777
720
|
async getOrSet(key, function_, options) {
|
|
721
|
+
const cacheAdapter = {
|
|
722
|
+
get: async (key2) => this.get(key2),
|
|
723
|
+
has: async (key2) => this.has(key2),
|
|
724
|
+
// biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
|
|
725
|
+
set: async (key2, value, ttl) => {
|
|
726
|
+
await this.set(key2, value, ttl);
|
|
727
|
+
},
|
|
728
|
+
/* c8 ignore start */
|
|
729
|
+
// biome-ignore lint/suspicious/noExplicitAny: CacheInstance interface
|
|
730
|
+
on: (event, listener) => {
|
|
731
|
+
this.on(event, listener);
|
|
732
|
+
},
|
|
733
|
+
/* c8 ignore stop */
|
|
734
|
+
// biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
|
|
735
|
+
emit: (event, ...args) => this.emit(event, ...args)
|
|
736
|
+
};
|
|
1778
737
|
const getOrSetOptions = {
|
|
1779
|
-
cache:
|
|
738
|
+
cache: cacheAdapter,
|
|
1780
739
|
cacheId: this._cacheId,
|
|
1781
740
|
ttl: options?.ttl ?? this._ttl,
|
|
1782
741
|
cacheErrors: options?.cacheErrors,
|
|
@@ -1790,39 +749,17 @@ var Cacheable = class extends Hookified2 {
|
|
|
1790
749
|
* @param {string} algorithm the hash algorithm to use. The default is 'sha256'
|
|
1791
750
|
* @returns {string} the hash of the object
|
|
1792
751
|
*/
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
return hash(object, algorithm);
|
|
1796
|
-
}
|
|
1797
|
-
async getSecondaryRawResults(key) {
|
|
1798
|
-
let result;
|
|
1799
|
-
if (this._secondary) {
|
|
1800
|
-
result = await this._secondary.get(key, { raw: true });
|
|
1801
|
-
}
|
|
1802
|
-
return result;
|
|
1803
|
-
}
|
|
1804
|
-
async getManySecondaryRawResults(keys) {
|
|
1805
|
-
let result = [];
|
|
1806
|
-
if (this._secondary) {
|
|
1807
|
-
result = await this._secondary.get(keys, { raw: true });
|
|
1808
|
-
}
|
|
1809
|
-
return result;
|
|
1810
|
-
}
|
|
1811
|
-
async deleteManyKeyv(keyv, keys) {
|
|
1812
|
-
const promises = [];
|
|
1813
|
-
for (const key of keys) {
|
|
1814
|
-
promises.push(keyv.delete(key));
|
|
1815
|
-
}
|
|
1816
|
-
await Promise.all(promises);
|
|
1817
|
-
return true;
|
|
752
|
+
hash(object, algorithm = HashAlgorithm.SHA256) {
|
|
753
|
+
const validAlgorithm = Object.values(HashAlgorithm).includes(algorithm) ? algorithm : HashAlgorithm.SHA256;
|
|
754
|
+
return hash(object, { algorithm: validAlgorithm });
|
|
1818
755
|
}
|
|
1819
756
|
async setManyKeyv(keyv, items) {
|
|
1820
|
-
const
|
|
757
|
+
const entries = [];
|
|
1821
758
|
for (const item of items) {
|
|
1822
759
|
const finalTtl = shorthandToMilliseconds(item.ttl ?? this._ttl);
|
|
1823
|
-
|
|
760
|
+
entries.push({ key: item.key, value: item.value, ttl: finalTtl });
|
|
1824
761
|
}
|
|
1825
|
-
await
|
|
762
|
+
await keyv.setMany(entries);
|
|
1826
763
|
return true;
|
|
1827
764
|
}
|
|
1828
765
|
async hasManyKeyv(keyv, keys) {
|
|
@@ -1832,6 +769,162 @@ var Cacheable = class extends Hookified2 {
|
|
|
1832
769
|
}
|
|
1833
770
|
return Promise.all(promises);
|
|
1834
771
|
}
|
|
772
|
+
/**
|
|
773
|
+
* Processes a single key from secondary store for getRaw operation
|
|
774
|
+
* @param primary - the primary store to use
|
|
775
|
+
* @param secondary - the secondary store to use
|
|
776
|
+
* @param key - The key to retrieve from secondary store
|
|
777
|
+
* @returns Promise containing the result and TTL information
|
|
778
|
+
*/
|
|
779
|
+
async processSecondaryForGetRaw(primary, secondary, key) {
|
|
780
|
+
const secondaryResult = await secondary.getRaw(key);
|
|
781
|
+
if (secondaryResult?.value) {
|
|
782
|
+
this.emit("cache:hit" /* CACHE_HIT */, {
|
|
783
|
+
key,
|
|
784
|
+
value: secondaryResult.value,
|
|
785
|
+
store: "secondary"
|
|
786
|
+
});
|
|
787
|
+
const cascadeTtl = getCascadingTtl(this._ttl, this._primary.ttl);
|
|
788
|
+
const expires = secondaryResult.expires ?? void 0;
|
|
789
|
+
const ttl = calculateTtlFromExpiration(cascadeTtl, expires);
|
|
790
|
+
const setItem = { key, value: secondaryResult.value, ttl };
|
|
791
|
+
await this.hook("BEFORE_SECONDARY_SETS_PRIMARY" /* BEFORE_SECONDARY_SETS_PRIMARY */, setItem);
|
|
792
|
+
await primary.set(setItem.key, setItem.value, setItem.ttl);
|
|
793
|
+
return { result: secondaryResult, ttl };
|
|
794
|
+
} else {
|
|
795
|
+
this.emit("cache:miss" /* CACHE_MISS */, { key, store: "secondary" });
|
|
796
|
+
return void 0;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Processes a single key from secondary store for getRaw operation in non-blocking mode
|
|
801
|
+
* Non-blocking mode means we don't wait for secondary operations that update primary store
|
|
802
|
+
* @param primary - the primary store to use
|
|
803
|
+
* @param secondary - the secondary store to use
|
|
804
|
+
* @param key - The key to retrieve from secondary store
|
|
805
|
+
* @returns Promise containing the result and TTL information
|
|
806
|
+
*/
|
|
807
|
+
async processSecondaryForGetRawNonBlocking(primary, secondary, key) {
|
|
808
|
+
const secondaryResult = await secondary.getRaw(key);
|
|
809
|
+
if (secondaryResult?.value) {
|
|
810
|
+
this.emit("cache:hit" /* CACHE_HIT */, {
|
|
811
|
+
key,
|
|
812
|
+
value: secondaryResult.value,
|
|
813
|
+
store: "secondary"
|
|
814
|
+
});
|
|
815
|
+
const cascadeTtl = getCascadingTtl(this._ttl, this._primary.ttl);
|
|
816
|
+
const expires = secondaryResult.expires ?? void 0;
|
|
817
|
+
const ttl = calculateTtlFromExpiration(cascadeTtl, expires);
|
|
818
|
+
const setItem = { key, value: secondaryResult.value, ttl };
|
|
819
|
+
this.hook("BEFORE_SECONDARY_SETS_PRIMARY" /* BEFORE_SECONDARY_SETS_PRIMARY */, setItem).then(async () => {
|
|
820
|
+
await primary.set(setItem.key, setItem.value, setItem.ttl);
|
|
821
|
+
}).catch((error) => {
|
|
822
|
+
this.emit("error" /* ERROR */, error);
|
|
823
|
+
});
|
|
824
|
+
return { result: secondaryResult, ttl };
|
|
825
|
+
} else {
|
|
826
|
+
this.emit("cache:miss" /* CACHE_MISS */, { key, store: "secondary" });
|
|
827
|
+
return void 0;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Processes missing keys from secondary store for getManyRaw operation
|
|
832
|
+
* @param primary - the primary store to use
|
|
833
|
+
* @param secondary - the secondary store to use
|
|
834
|
+
* @param keys - The original array of keys requested
|
|
835
|
+
* @param result - The result array from primary store (will be modified)
|
|
836
|
+
* @returns Promise<void>
|
|
837
|
+
*/
|
|
838
|
+
async processSecondaryForGetManyRaw(primary, secondary, keys, result) {
|
|
839
|
+
const missingKeys = [];
|
|
840
|
+
for (const [i, key] of keys.entries()) {
|
|
841
|
+
if (!result[i]) {
|
|
842
|
+
missingKeys.push(key);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
const secondaryResults = await secondary.getManyRaw(missingKeys);
|
|
846
|
+
let secondaryIndex = 0;
|
|
847
|
+
for await (const [i, key] of keys.entries()) {
|
|
848
|
+
if (!result[i]) {
|
|
849
|
+
const secondaryResult = secondaryResults[secondaryIndex];
|
|
850
|
+
if (secondaryResult && secondaryResult.value !== void 0) {
|
|
851
|
+
result[i] = secondaryResult;
|
|
852
|
+
this.emit("cache:hit" /* CACHE_HIT */, {
|
|
853
|
+
key,
|
|
854
|
+
value: secondaryResult.value,
|
|
855
|
+
store: "secondary"
|
|
856
|
+
});
|
|
857
|
+
const cascadeTtl = getCascadingTtl(this._ttl, this._primary.ttl);
|
|
858
|
+
let { expires } = secondaryResult;
|
|
859
|
+
if (expires === null) {
|
|
860
|
+
expires = void 0;
|
|
861
|
+
}
|
|
862
|
+
const ttl = calculateTtlFromExpiration(cascadeTtl, expires);
|
|
863
|
+
const setItem = { key, value: secondaryResult.value, ttl };
|
|
864
|
+
await this.hook(
|
|
865
|
+
"BEFORE_SECONDARY_SETS_PRIMARY" /* BEFORE_SECONDARY_SETS_PRIMARY */,
|
|
866
|
+
setItem
|
|
867
|
+
);
|
|
868
|
+
await primary.set(setItem.key, setItem.value, setItem.ttl);
|
|
869
|
+
} else {
|
|
870
|
+
this.emit("cache:miss" /* CACHE_MISS */, {
|
|
871
|
+
key,
|
|
872
|
+
store: "secondary"
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
secondaryIndex++;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Processes missing keys from secondary store for getManyRaw operation in non-blocking mode
|
|
881
|
+
* Non-blocking mode means we don't wait for secondary operations that update primary store
|
|
882
|
+
* @param secondary - the secondary store to use
|
|
883
|
+
* @param keys - The original array of keys requested
|
|
884
|
+
* @param result - The result array from primary store (will be modified)
|
|
885
|
+
* @returns Promise<void>
|
|
886
|
+
*/
|
|
887
|
+
async processSecondaryForGetManyRawNonBlocking(primary, secondary, keys, result) {
|
|
888
|
+
const missingKeys = [];
|
|
889
|
+
for (const [i, key] of keys.entries()) {
|
|
890
|
+
if (!result[i]) {
|
|
891
|
+
missingKeys.push(key);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
const secondaryResults = await secondary.getManyRaw(missingKeys);
|
|
895
|
+
let secondaryIndex = 0;
|
|
896
|
+
for await (const [i, key] of keys.entries()) {
|
|
897
|
+
if (!result[i]) {
|
|
898
|
+
const secondaryResult = secondaryResults[secondaryIndex];
|
|
899
|
+
if (secondaryResult && secondaryResult.value !== void 0) {
|
|
900
|
+
result[i] = secondaryResult;
|
|
901
|
+
this.emit("cache:hit" /* CACHE_HIT */, {
|
|
902
|
+
key,
|
|
903
|
+
value: secondaryResult.value,
|
|
904
|
+
store: "secondary"
|
|
905
|
+
});
|
|
906
|
+
const cascadeTtl = getCascadingTtl(this._ttl, this._primary.ttl);
|
|
907
|
+
let { expires } = secondaryResult;
|
|
908
|
+
if (expires === null) {
|
|
909
|
+
expires = void 0;
|
|
910
|
+
}
|
|
911
|
+
const ttl = calculateTtlFromExpiration(cascadeTtl, expires);
|
|
912
|
+
const setItem = { key, value: secondaryResult.value, ttl };
|
|
913
|
+
this.hook("BEFORE_SECONDARY_SETS_PRIMARY" /* BEFORE_SECONDARY_SETS_PRIMARY */, setItem).then(async () => {
|
|
914
|
+
await primary.set(setItem.key, setItem.value, setItem.ttl);
|
|
915
|
+
}).catch((error) => {
|
|
916
|
+
this.emit("error" /* ERROR */, error);
|
|
917
|
+
});
|
|
918
|
+
} else {
|
|
919
|
+
this.emit("cache:miss" /* CACHE_MISS */, {
|
|
920
|
+
key,
|
|
921
|
+
store: "secondary"
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
secondaryIndex++;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
1835
928
|
setTtl(ttl) {
|
|
1836
929
|
if (typeof ttl === "string" || ttl === void 0) {
|
|
1837
930
|
this._ttl = ttl;
|
|
@@ -1847,14 +940,18 @@ export {
|
|
|
1847
940
|
CacheableEvents,
|
|
1848
941
|
CacheableHooks,
|
|
1849
942
|
CacheableMemory,
|
|
1850
|
-
CacheableStats,
|
|
1851
|
-
|
|
943
|
+
Stats as CacheableStats,
|
|
944
|
+
HashAlgorithm2 as HashAlgorithm,
|
|
945
|
+
Keyv2 as Keyv,
|
|
1852
946
|
KeyvCacheableMemory,
|
|
1853
947
|
KeyvHooks,
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
948
|
+
calculateTtlFromExpiration2 as calculateTtlFromExpiration,
|
|
949
|
+
createKeyv2 as createKeyv,
|
|
950
|
+
getCascadingTtl2 as getCascadingTtl,
|
|
951
|
+
getOrSet2 as getOrSet,
|
|
952
|
+
hash2 as hash,
|
|
953
|
+
shorthandToMilliseconds2 as shorthandToMilliseconds,
|
|
1857
954
|
shorthandToTime,
|
|
1858
|
-
wrap,
|
|
955
|
+
wrap2 as wrap,
|
|
1859
956
|
wrapSync
|
|
1860
957
|
};
|