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