cacheable 1.8.4 → 1.8.6
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 +16 -5
- package/dist/index.cjs +80 -25
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +80 -24
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
[<img align="center" src="https://cacheable.org/logo.svg" alt="Cacheable" />](https://github.com/jaredwray/cacheable)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
> Simple Caching Engine using Keyv
|
|
3
|
+
> High Performance Layer 1 / Layer 2 Caching with Keyv Storage
|
|
6
4
|
|
|
7
5
|
[](https://codecov.io/gh/jaredwray/cacheable)
|
|
8
6
|
[](https://github.com/jaredwray/cacheable/actions/workflows/tests.yml)
|
|
@@ -347,11 +345,24 @@ const cache = new CacheableMemory();
|
|
|
347
345
|
const wrappedFunction = cache.wrap(syncFunction, { ttl: '1h', key: 'syncFunction' });
|
|
348
346
|
console.log(wrappedFunction(2)); // 4
|
|
349
347
|
console.log(wrappedFunction(2)); // 4 from cache
|
|
350
|
-
console.log(cache.get('syncFunction')); // 4
|
|
351
348
|
```
|
|
352
349
|
|
|
353
350
|
In this example we are wrapping a `sync` function in a cache with a `ttl` of `1 hour`. This will cache the result of the function for `1 hour` and then expire the value. You can also set the `key` property in the `wrap()` options to set a custom key for the cache.
|
|
354
351
|
|
|
352
|
+
When an error occurs in the function it will not cache the value and will return the error. This is useful if you want to cache the results of a function but not cache the error. If you want it to cache the error you can set the `cacheError` property to `true` in the `wrap()` options. This is disabled by default.
|
|
353
|
+
|
|
354
|
+
```javascript
|
|
355
|
+
import { CacheableMemory } from 'cacheable';
|
|
356
|
+
const syncFunction = (value: number) => {
|
|
357
|
+
throw new Error('error');
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const cache = new CacheableMemory();
|
|
361
|
+
const wrappedFunction = cache.wrap(syncFunction, { ttl: '1h', key: 'syncFunction', cacheError: true });
|
|
362
|
+
console.log(wrappedFunction()); // error
|
|
363
|
+
console.log(wrappedFunction()); // error from cache
|
|
364
|
+
```
|
|
365
|
+
|
|
355
366
|
# Keyv Storage Adapter - KeyvCacheableMemory
|
|
356
367
|
|
|
357
368
|
`cacheable` comes with a built-in storage adapter for Keyv called `KeyvCacheableMemory`. This takes `CacheableMemory` and creates a storage adapter for Keyv. This is useful if you want to use `CacheableMemory` as a storage adapter for Keyv. Here is an example of how to use `KeyvCacheableMemory`:
|
|
@@ -362,7 +373,7 @@ import { KeyvCacheableMemory } from 'cacheable';
|
|
|
362
373
|
|
|
363
374
|
const keyv = new Keyv({ store: new KeyvCacheableMemory() });
|
|
364
375
|
await keyv.set('foo', 'bar');
|
|
365
|
-
const value = await keyv.get('
|
|
376
|
+
const value = await keyv.get('foo');
|
|
366
377
|
console.log(value); // bar
|
|
367
378
|
```
|
|
368
379
|
|
package/dist/index.cjs
CHANGED
|
@@ -35,17 +35,18 @@ __export(src_exports, {
|
|
|
35
35
|
CacheableHooks: () => CacheableHooks,
|
|
36
36
|
CacheableMemory: () => CacheableMemory,
|
|
37
37
|
CacheableStats: () => CacheableStats,
|
|
38
|
-
Keyv: () =>
|
|
38
|
+
Keyv: () => import_keyv3.Keyv,
|
|
39
39
|
KeyvCacheableMemory: () => KeyvCacheableMemory,
|
|
40
|
-
KeyvHooks: () =>
|
|
40
|
+
KeyvHooks: () => import_keyv3.KeyvHooks,
|
|
41
|
+
createKeyv: () => createKeyv,
|
|
41
42
|
shorthandToMilliseconds: () => shorthandToMilliseconds,
|
|
42
43
|
shorthandToTime: () => shorthandToTime,
|
|
43
44
|
wrap: () => wrap,
|
|
44
45
|
wrapSync: () => wrapSync
|
|
45
46
|
});
|
|
46
47
|
module.exports = __toCommonJS(src_exports);
|
|
47
|
-
var
|
|
48
|
-
var
|
|
48
|
+
var import_keyv2 = require("keyv");
|
|
49
|
+
var import_hookified2 = require("hookified");
|
|
49
50
|
|
|
50
51
|
// src/shorthand-time.ts
|
|
51
52
|
var shorthandToMilliseconds = (shorthand) => {
|
|
@@ -114,6 +115,12 @@ var shorthandToTime = (shorthand, fromDate) => {
|
|
|
114
115
|
return fromDate.getTime() + milliseconds;
|
|
115
116
|
};
|
|
116
117
|
|
|
118
|
+
// src/keyv-memory.ts
|
|
119
|
+
var import_keyv = require("keyv");
|
|
120
|
+
|
|
121
|
+
// src/memory.ts
|
|
122
|
+
var import_hookified = require("hookified");
|
|
123
|
+
|
|
117
124
|
// src/hash.ts
|
|
118
125
|
var crypto = __toESM(require("crypto"), 1);
|
|
119
126
|
function hash(object, algorithm = "sha256") {
|
|
@@ -188,8 +195,15 @@ function wrapSync(function_, options) {
|
|
|
188
195
|
const cacheKey = createWrapKey(function_, arguments_, keyPrefix);
|
|
189
196
|
let value = cache.get(cacheKey);
|
|
190
197
|
if (value === void 0) {
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
try {
|
|
199
|
+
value = function_(...arguments_);
|
|
200
|
+
cache.set(cacheKey, value, ttl);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
cache.emit("error", error);
|
|
203
|
+
if (options.cacheErrors) {
|
|
204
|
+
cache.set(cacheKey, error, ttl);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
193
207
|
}
|
|
194
208
|
return value;
|
|
195
209
|
};
|
|
@@ -198,17 +212,21 @@ function wrap(function_, options) {
|
|
|
198
212
|
const { ttl, keyPrefix, cache } = options;
|
|
199
213
|
return async function(...arguments_) {
|
|
200
214
|
let value;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
215
|
+
const cacheKey = createWrapKey(function_, arguments_, keyPrefix);
|
|
216
|
+
value = await cache.get(cacheKey);
|
|
217
|
+
if (value === void 0) {
|
|
218
|
+
value = await coalesceAsync(cacheKey, async () => {
|
|
219
|
+
try {
|
|
206
220
|
const result = await function_(...arguments_);
|
|
207
221
|
await cache.set(cacheKey, result, ttl);
|
|
208
222
|
return result;
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
|
|
223
|
+
} catch (error) {
|
|
224
|
+
cache.emit("error", error);
|
|
225
|
+
if (options.cacheErrors) {
|
|
226
|
+
await cache.set(cacheKey, error, ttl);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
});
|
|
212
230
|
}
|
|
213
231
|
return value;
|
|
214
232
|
};
|
|
@@ -294,7 +312,7 @@ var DoublyLinkedList = class {
|
|
|
294
312
|
};
|
|
295
313
|
|
|
296
314
|
// src/memory.ts
|
|
297
|
-
var CacheableMemory = class {
|
|
315
|
+
var CacheableMemory = class extends import_hookified.Hookified {
|
|
298
316
|
_lru = new DoublyLinkedList();
|
|
299
317
|
_hashCache = /* @__PURE__ */ new Map();
|
|
300
318
|
_hash0 = /* @__PURE__ */ new Map();
|
|
@@ -322,6 +340,7 @@ var CacheableMemory = class {
|
|
|
322
340
|
* @param {CacheableMemoryOptions} [options] - The options for the CacheableMemory
|
|
323
341
|
*/
|
|
324
342
|
constructor(options) {
|
|
343
|
+
super();
|
|
325
344
|
if (options?.ttl) {
|
|
326
345
|
this.setTtl(options.ttl);
|
|
327
346
|
}
|
|
@@ -481,7 +500,8 @@ var CacheableMemory = class {
|
|
|
481
500
|
* Sets the value of the key
|
|
482
501
|
* @param {string} key - The key to set the value
|
|
483
502
|
* @param {any} value - The value to set
|
|
484
|
-
* @param {number|string} [ttl] - Time to Live - If you set a number it is miliseconds, if you set a string it is a human-readable.
|
|
503
|
+
* @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.
|
|
504
|
+
* If you want to set expire directly you can do that by setting the expire property in the SetOptions.
|
|
485
505
|
* 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.
|
|
486
506
|
* @returns {void}
|
|
487
507
|
*/
|
|
@@ -489,9 +509,21 @@ var CacheableMemory = class {
|
|
|
489
509
|
const store = this.getStore(key);
|
|
490
510
|
let expires;
|
|
491
511
|
if (ttl !== void 0 || this._ttl !== void 0) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
512
|
+
if (typeof ttl === "object") {
|
|
513
|
+
if (ttl.expire) {
|
|
514
|
+
expires = typeof ttl.expire === "number" ? ttl.expire : ttl.expire.getTime();
|
|
515
|
+
}
|
|
516
|
+
if (ttl.ttl) {
|
|
517
|
+
const finalTtl = shorthandToTime(ttl.ttl);
|
|
518
|
+
if (finalTtl !== void 0) {
|
|
519
|
+
expires = finalTtl;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
const finalTtl = shorthandToTime(ttl ?? this._ttl);
|
|
524
|
+
if (finalTtl !== void 0) {
|
|
525
|
+
expires = finalTtl;
|
|
526
|
+
}
|
|
495
527
|
}
|
|
496
528
|
}
|
|
497
529
|
if (this._lruSize > 0) {
|
|
@@ -742,9 +774,12 @@ var CacheableMemory = class {
|
|
|
742
774
|
*/
|
|
743
775
|
startIntervalCheck() {
|
|
744
776
|
if (this._checkInterval > 0) {
|
|
777
|
+
if (this._interval) {
|
|
778
|
+
clearInterval(this._interval);
|
|
779
|
+
}
|
|
745
780
|
this._interval = setInterval(() => {
|
|
746
781
|
this.checkExpiration();
|
|
747
|
-
}, this._checkInterval);
|
|
782
|
+
}, this._checkInterval).unref();
|
|
748
783
|
}
|
|
749
784
|
}
|
|
750
785
|
/**
|
|
@@ -867,6 +902,7 @@ var KeyvCacheableMemory = class {
|
|
|
867
902
|
return this.getStore(this._namespace).has(key);
|
|
868
903
|
}
|
|
869
904
|
on(event, listener) {
|
|
905
|
+
this.getStore(this._namespace).on(event, listener);
|
|
870
906
|
return this;
|
|
871
907
|
}
|
|
872
908
|
getStore(namespace) {
|
|
@@ -879,6 +915,18 @@ var KeyvCacheableMemory = class {
|
|
|
879
915
|
return this._nCache.get(namespace);
|
|
880
916
|
}
|
|
881
917
|
};
|
|
918
|
+
function createKeyv(options) {
|
|
919
|
+
const store = new KeyvCacheableMemory(options);
|
|
920
|
+
const namespace = options?.namespace;
|
|
921
|
+
let ttl;
|
|
922
|
+
if (options?.ttl && Number.isInteger(options.ttl)) {
|
|
923
|
+
ttl = options?.ttl;
|
|
924
|
+
}
|
|
925
|
+
const keyv = new import_keyv.Keyv({ store, namespace, ttl });
|
|
926
|
+
keyv.serialize = void 0;
|
|
927
|
+
keyv.deserialize = void 0;
|
|
928
|
+
return keyv;
|
|
929
|
+
}
|
|
882
930
|
|
|
883
931
|
// src/stats.ts
|
|
884
932
|
var CacheableStats = class {
|
|
@@ -1098,7 +1146,7 @@ var CacheableStats = class {
|
|
|
1098
1146
|
};
|
|
1099
1147
|
|
|
1100
1148
|
// src/index.ts
|
|
1101
|
-
var
|
|
1149
|
+
var import_keyv3 = require("keyv");
|
|
1102
1150
|
var CacheableHooks = /* @__PURE__ */ ((CacheableHooks2) => {
|
|
1103
1151
|
CacheableHooks2["BEFORE_SET"] = "BEFORE_SET";
|
|
1104
1152
|
CacheableHooks2["AFTER_SET"] = "AFTER_SET";
|
|
@@ -1114,8 +1162,8 @@ var CacheableEvents = /* @__PURE__ */ ((CacheableEvents2) => {
|
|
|
1114
1162
|
CacheableEvents2["ERROR"] = "error";
|
|
1115
1163
|
return CacheableEvents2;
|
|
1116
1164
|
})(CacheableEvents || {});
|
|
1117
|
-
var Cacheable = class extends
|
|
1118
|
-
_primary =
|
|
1165
|
+
var Cacheable = class extends import_hookified2.Hookified {
|
|
1166
|
+
_primary = createKeyv();
|
|
1119
1167
|
_secondary;
|
|
1120
1168
|
_nonBlocking = false;
|
|
1121
1169
|
_ttl;
|
|
@@ -1274,7 +1322,10 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
1274
1322
|
* @returns {void}
|
|
1275
1323
|
*/
|
|
1276
1324
|
setPrimary(primary) {
|
|
1277
|
-
this._primary = primary instanceof
|
|
1325
|
+
this._primary = primary instanceof import_keyv2.Keyv ? primary : new import_keyv2.Keyv(primary);
|
|
1326
|
+
this._primary.on("error", (error) => {
|
|
1327
|
+
this.emit("error" /* ERROR */, error);
|
|
1328
|
+
});
|
|
1278
1329
|
}
|
|
1279
1330
|
/**
|
|
1280
1331
|
* Sets the secondary store for the cacheable instance. If it is set to undefined then the secondary store is disabled.
|
|
@@ -1282,7 +1333,10 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
1282
1333
|
* @returns {void}
|
|
1283
1334
|
*/
|
|
1284
1335
|
setSecondary(secondary) {
|
|
1285
|
-
this._secondary = secondary instanceof
|
|
1336
|
+
this._secondary = secondary instanceof import_keyv2.Keyv ? secondary : new import_keyv2.Keyv(secondary);
|
|
1337
|
+
this._secondary.on("error", (error) => {
|
|
1338
|
+
this.emit("error" /* ERROR */, error);
|
|
1339
|
+
});
|
|
1286
1340
|
}
|
|
1287
1341
|
getNameSpace() {
|
|
1288
1342
|
if (typeof this._namespace === "function") {
|
|
@@ -1643,6 +1697,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
1643
1697
|
Keyv,
|
|
1644
1698
|
KeyvCacheableMemory,
|
|
1645
1699
|
KeyvHooks,
|
|
1700
|
+
createKeyv,
|
|
1646
1701
|
shorthandToMilliseconds,
|
|
1647
1702
|
shorthandToTime,
|
|
1648
1703
|
wrap,
|
package/dist/index.d.cts
CHANGED
|
@@ -112,6 +112,7 @@ type CacheableStoreItem = {
|
|
|
112
112
|
type WrapFunctionOptions = {
|
|
113
113
|
ttl?: number | string;
|
|
114
114
|
keyPrefix?: string;
|
|
115
|
+
cacheErrors?: boolean;
|
|
115
116
|
};
|
|
116
117
|
type WrapOptions = WrapFunctionOptions & {
|
|
117
118
|
cache: Cacheable;
|
|
@@ -138,7 +139,11 @@ type CacheableMemoryOptions = {
|
|
|
138
139
|
lruSize?: number;
|
|
139
140
|
checkInterval?: number;
|
|
140
141
|
};
|
|
141
|
-
|
|
142
|
+
type SetOptions = {
|
|
143
|
+
ttl?: number | string;
|
|
144
|
+
expire?: number | Date;
|
|
145
|
+
};
|
|
146
|
+
declare class CacheableMemory extends Hookified {
|
|
142
147
|
private _lru;
|
|
143
148
|
private readonly _hashCache;
|
|
144
149
|
private readonly _hash0;
|
|
@@ -244,11 +249,12 @@ declare class CacheableMemory {
|
|
|
244
249
|
* Sets the value of the key
|
|
245
250
|
* @param {string} key - The key to set the value
|
|
246
251
|
* @param {any} value - The value to set
|
|
247
|
-
* @param {number|string} [ttl] - Time to Live - If you set a number it is miliseconds, if you set a string it is a human-readable.
|
|
252
|
+
* @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.
|
|
253
|
+
* If you want to set expire directly you can do that by setting the expire property in the SetOptions.
|
|
248
254
|
* 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.
|
|
249
255
|
* @returns {void}
|
|
250
256
|
*/
|
|
251
|
-
set(key: string, value: any, ttl?: number | string): void;
|
|
257
|
+
set(key: string, value: any, ttl?: number | string | SetOptions): void;
|
|
252
258
|
/**
|
|
253
259
|
* Sets the values of the keys
|
|
254
260
|
* @param {CacheableItem[]} items - The items to set
|
|
@@ -398,6 +404,12 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
|
398
404
|
on(event: string, listener: (...arguments_: any[]) => void): this;
|
|
399
405
|
getStore(namespace?: string): CacheableMemory;
|
|
400
406
|
}
|
|
407
|
+
/**
|
|
408
|
+
* Creates a new Keyv instance with a new KeyvCacheableMemory store. This also removes the serialize/deserialize methods from the Keyv instance for optimization.
|
|
409
|
+
* @param options
|
|
410
|
+
* @returns
|
|
411
|
+
*/
|
|
412
|
+
declare function createKeyv(options?: KeyvCacheableMemoryOptions): Keyv;
|
|
401
413
|
|
|
402
414
|
declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
|
|
403
415
|
declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
|
|
@@ -635,4 +647,4 @@ declare class Cacheable extends Hookified {
|
|
|
635
647
|
private setTtl;
|
|
636
648
|
}
|
|
637
649
|
|
|
638
|
-
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableMemoryOptions, type CacheableOptions, CacheableStats, KeyvCacheableMemory, type WrapOptions, type WrapSyncOptions, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync };
|
|
650
|
+
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableMemoryOptions, type CacheableOptions, CacheableStats, KeyvCacheableMemory, type WrapOptions, type WrapSyncOptions, createKeyv, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync };
|
package/dist/index.d.ts
CHANGED
|
@@ -112,6 +112,7 @@ type CacheableStoreItem = {
|
|
|
112
112
|
type WrapFunctionOptions = {
|
|
113
113
|
ttl?: number | string;
|
|
114
114
|
keyPrefix?: string;
|
|
115
|
+
cacheErrors?: boolean;
|
|
115
116
|
};
|
|
116
117
|
type WrapOptions = WrapFunctionOptions & {
|
|
117
118
|
cache: Cacheable;
|
|
@@ -138,7 +139,11 @@ type CacheableMemoryOptions = {
|
|
|
138
139
|
lruSize?: number;
|
|
139
140
|
checkInterval?: number;
|
|
140
141
|
};
|
|
141
|
-
|
|
142
|
+
type SetOptions = {
|
|
143
|
+
ttl?: number | string;
|
|
144
|
+
expire?: number | Date;
|
|
145
|
+
};
|
|
146
|
+
declare class CacheableMemory extends Hookified {
|
|
142
147
|
private _lru;
|
|
143
148
|
private readonly _hashCache;
|
|
144
149
|
private readonly _hash0;
|
|
@@ -244,11 +249,12 @@ declare class CacheableMemory {
|
|
|
244
249
|
* Sets the value of the key
|
|
245
250
|
* @param {string} key - The key to set the value
|
|
246
251
|
* @param {any} value - The value to set
|
|
247
|
-
* @param {number|string} [ttl] - Time to Live - If you set a number it is miliseconds, if you set a string it is a human-readable.
|
|
252
|
+
* @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.
|
|
253
|
+
* If you want to set expire directly you can do that by setting the expire property in the SetOptions.
|
|
248
254
|
* 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.
|
|
249
255
|
* @returns {void}
|
|
250
256
|
*/
|
|
251
|
-
set(key: string, value: any, ttl?: number | string): void;
|
|
257
|
+
set(key: string, value: any, ttl?: number | string | SetOptions): void;
|
|
252
258
|
/**
|
|
253
259
|
* Sets the values of the keys
|
|
254
260
|
* @param {CacheableItem[]} items - The items to set
|
|
@@ -398,6 +404,12 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
|
398
404
|
on(event: string, listener: (...arguments_: any[]) => void): this;
|
|
399
405
|
getStore(namespace?: string): CacheableMemory;
|
|
400
406
|
}
|
|
407
|
+
/**
|
|
408
|
+
* Creates a new Keyv instance with a new KeyvCacheableMemory store. This also removes the serialize/deserialize methods from the Keyv instance for optimization.
|
|
409
|
+
* @param options
|
|
410
|
+
* @returns
|
|
411
|
+
*/
|
|
412
|
+
declare function createKeyv(options?: KeyvCacheableMemoryOptions): Keyv;
|
|
401
413
|
|
|
402
414
|
declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
|
|
403
415
|
declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
|
|
@@ -635,4 +647,4 @@ declare class Cacheable extends Hookified {
|
|
|
635
647
|
private setTtl;
|
|
636
648
|
}
|
|
637
649
|
|
|
638
|
-
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableMemoryOptions, type CacheableOptions, CacheableStats, KeyvCacheableMemory, type WrapOptions, type WrapSyncOptions, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync };
|
|
650
|
+
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableMemoryOptions, type CacheableOptions, CacheableStats, KeyvCacheableMemory, type WrapOptions, type WrapSyncOptions, createKeyv, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { Keyv } from "keyv";
|
|
3
|
-
import { Hookified } from "hookified";
|
|
2
|
+
import { Keyv as Keyv2 } from "keyv";
|
|
3
|
+
import { Hookified as Hookified2 } from "hookified";
|
|
4
4
|
|
|
5
5
|
// src/shorthand-time.ts
|
|
6
6
|
var shorthandToMilliseconds = (shorthand) => {
|
|
@@ -69,6 +69,14 @@ var shorthandToTime = (shorthand, fromDate) => {
|
|
|
69
69
|
return fromDate.getTime() + milliseconds;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
+
// src/keyv-memory.ts
|
|
73
|
+
import {
|
|
74
|
+
Keyv
|
|
75
|
+
} from "keyv";
|
|
76
|
+
|
|
77
|
+
// src/memory.ts
|
|
78
|
+
import { Hookified } from "hookified";
|
|
79
|
+
|
|
72
80
|
// src/hash.ts
|
|
73
81
|
import * as crypto from "node:crypto";
|
|
74
82
|
function hash(object, algorithm = "sha256") {
|
|
@@ -143,8 +151,15 @@ function wrapSync(function_, options) {
|
|
|
143
151
|
const cacheKey = createWrapKey(function_, arguments_, keyPrefix);
|
|
144
152
|
let value = cache.get(cacheKey);
|
|
145
153
|
if (value === void 0) {
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
try {
|
|
155
|
+
value = function_(...arguments_);
|
|
156
|
+
cache.set(cacheKey, value, ttl);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
cache.emit("error", error);
|
|
159
|
+
if (options.cacheErrors) {
|
|
160
|
+
cache.set(cacheKey, error, ttl);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
148
163
|
}
|
|
149
164
|
return value;
|
|
150
165
|
};
|
|
@@ -153,17 +168,21 @@ function wrap(function_, options) {
|
|
|
153
168
|
const { ttl, keyPrefix, cache } = options;
|
|
154
169
|
return async function(...arguments_) {
|
|
155
170
|
let value;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
const cacheKey = createWrapKey(function_, arguments_, keyPrefix);
|
|
172
|
+
value = await cache.get(cacheKey);
|
|
173
|
+
if (value === void 0) {
|
|
174
|
+
value = await coalesceAsync(cacheKey, async () => {
|
|
175
|
+
try {
|
|
161
176
|
const result = await function_(...arguments_);
|
|
162
177
|
await cache.set(cacheKey, result, ttl);
|
|
163
178
|
return result;
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
|
|
179
|
+
} catch (error) {
|
|
180
|
+
cache.emit("error", error);
|
|
181
|
+
if (options.cacheErrors) {
|
|
182
|
+
await cache.set(cacheKey, error, ttl);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
});
|
|
167
186
|
}
|
|
168
187
|
return value;
|
|
169
188
|
};
|
|
@@ -249,7 +268,7 @@ var DoublyLinkedList = class {
|
|
|
249
268
|
};
|
|
250
269
|
|
|
251
270
|
// src/memory.ts
|
|
252
|
-
var CacheableMemory = class {
|
|
271
|
+
var CacheableMemory = class extends Hookified {
|
|
253
272
|
_lru = new DoublyLinkedList();
|
|
254
273
|
_hashCache = /* @__PURE__ */ new Map();
|
|
255
274
|
_hash0 = /* @__PURE__ */ new Map();
|
|
@@ -277,6 +296,7 @@ var CacheableMemory = class {
|
|
|
277
296
|
* @param {CacheableMemoryOptions} [options] - The options for the CacheableMemory
|
|
278
297
|
*/
|
|
279
298
|
constructor(options) {
|
|
299
|
+
super();
|
|
280
300
|
if (options?.ttl) {
|
|
281
301
|
this.setTtl(options.ttl);
|
|
282
302
|
}
|
|
@@ -436,7 +456,8 @@ var CacheableMemory = class {
|
|
|
436
456
|
* Sets the value of the key
|
|
437
457
|
* @param {string} key - The key to set the value
|
|
438
458
|
* @param {any} value - The value to set
|
|
439
|
-
* @param {number|string} [ttl] - Time to Live - If you set a number it is miliseconds, if you set a string it is a human-readable.
|
|
459
|
+
* @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.
|
|
460
|
+
* If you want to set expire directly you can do that by setting the expire property in the SetOptions.
|
|
440
461
|
* 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.
|
|
441
462
|
* @returns {void}
|
|
442
463
|
*/
|
|
@@ -444,9 +465,21 @@ var CacheableMemory = class {
|
|
|
444
465
|
const store = this.getStore(key);
|
|
445
466
|
let expires;
|
|
446
467
|
if (ttl !== void 0 || this._ttl !== void 0) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
468
|
+
if (typeof ttl === "object") {
|
|
469
|
+
if (ttl.expire) {
|
|
470
|
+
expires = typeof ttl.expire === "number" ? ttl.expire : ttl.expire.getTime();
|
|
471
|
+
}
|
|
472
|
+
if (ttl.ttl) {
|
|
473
|
+
const finalTtl = shorthandToTime(ttl.ttl);
|
|
474
|
+
if (finalTtl !== void 0) {
|
|
475
|
+
expires = finalTtl;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
} else {
|
|
479
|
+
const finalTtl = shorthandToTime(ttl ?? this._ttl);
|
|
480
|
+
if (finalTtl !== void 0) {
|
|
481
|
+
expires = finalTtl;
|
|
482
|
+
}
|
|
450
483
|
}
|
|
451
484
|
}
|
|
452
485
|
if (this._lruSize > 0) {
|
|
@@ -697,9 +730,12 @@ var CacheableMemory = class {
|
|
|
697
730
|
*/
|
|
698
731
|
startIntervalCheck() {
|
|
699
732
|
if (this._checkInterval > 0) {
|
|
733
|
+
if (this._interval) {
|
|
734
|
+
clearInterval(this._interval);
|
|
735
|
+
}
|
|
700
736
|
this._interval = setInterval(() => {
|
|
701
737
|
this.checkExpiration();
|
|
702
|
-
}, this._checkInterval);
|
|
738
|
+
}, this._checkInterval).unref();
|
|
703
739
|
}
|
|
704
740
|
}
|
|
705
741
|
/**
|
|
@@ -822,6 +858,7 @@ var KeyvCacheableMemory = class {
|
|
|
822
858
|
return this.getStore(this._namespace).has(key);
|
|
823
859
|
}
|
|
824
860
|
on(event, listener) {
|
|
861
|
+
this.getStore(this._namespace).on(event, listener);
|
|
825
862
|
return this;
|
|
826
863
|
}
|
|
827
864
|
getStore(namespace) {
|
|
@@ -834,6 +871,18 @@ var KeyvCacheableMemory = class {
|
|
|
834
871
|
return this._nCache.get(namespace);
|
|
835
872
|
}
|
|
836
873
|
};
|
|
874
|
+
function createKeyv(options) {
|
|
875
|
+
const store = new KeyvCacheableMemory(options);
|
|
876
|
+
const namespace = options?.namespace;
|
|
877
|
+
let ttl;
|
|
878
|
+
if (options?.ttl && Number.isInteger(options.ttl)) {
|
|
879
|
+
ttl = options?.ttl;
|
|
880
|
+
}
|
|
881
|
+
const keyv = new Keyv({ store, namespace, ttl });
|
|
882
|
+
keyv.serialize = void 0;
|
|
883
|
+
keyv.deserialize = void 0;
|
|
884
|
+
return keyv;
|
|
885
|
+
}
|
|
837
886
|
|
|
838
887
|
// src/stats.ts
|
|
839
888
|
var CacheableStats = class {
|
|
@@ -1055,7 +1104,7 @@ var CacheableStats = class {
|
|
|
1055
1104
|
// src/index.ts
|
|
1056
1105
|
import {
|
|
1057
1106
|
KeyvHooks,
|
|
1058
|
-
Keyv as
|
|
1107
|
+
Keyv as Keyv3
|
|
1059
1108
|
} from "keyv";
|
|
1060
1109
|
var CacheableHooks = /* @__PURE__ */ ((CacheableHooks2) => {
|
|
1061
1110
|
CacheableHooks2["BEFORE_SET"] = "BEFORE_SET";
|
|
@@ -1072,8 +1121,8 @@ var CacheableEvents = /* @__PURE__ */ ((CacheableEvents2) => {
|
|
|
1072
1121
|
CacheableEvents2["ERROR"] = "error";
|
|
1073
1122
|
return CacheableEvents2;
|
|
1074
1123
|
})(CacheableEvents || {});
|
|
1075
|
-
var Cacheable = class extends
|
|
1076
|
-
_primary =
|
|
1124
|
+
var Cacheable = class extends Hookified2 {
|
|
1125
|
+
_primary = createKeyv();
|
|
1077
1126
|
_secondary;
|
|
1078
1127
|
_nonBlocking = false;
|
|
1079
1128
|
_ttl;
|
|
@@ -1232,7 +1281,10 @@ var Cacheable = class extends Hookified {
|
|
|
1232
1281
|
* @returns {void}
|
|
1233
1282
|
*/
|
|
1234
1283
|
setPrimary(primary) {
|
|
1235
|
-
this._primary = primary instanceof
|
|
1284
|
+
this._primary = primary instanceof Keyv2 ? primary : new Keyv2(primary);
|
|
1285
|
+
this._primary.on("error", (error) => {
|
|
1286
|
+
this.emit("error" /* ERROR */, error);
|
|
1287
|
+
});
|
|
1236
1288
|
}
|
|
1237
1289
|
/**
|
|
1238
1290
|
* Sets the secondary store for the cacheable instance. If it is set to undefined then the secondary store is disabled.
|
|
@@ -1240,7 +1292,10 @@ var Cacheable = class extends Hookified {
|
|
|
1240
1292
|
* @returns {void}
|
|
1241
1293
|
*/
|
|
1242
1294
|
setSecondary(secondary) {
|
|
1243
|
-
this._secondary = secondary instanceof
|
|
1295
|
+
this._secondary = secondary instanceof Keyv2 ? secondary : new Keyv2(secondary);
|
|
1296
|
+
this._secondary.on("error", (error) => {
|
|
1297
|
+
this.emit("error" /* ERROR */, error);
|
|
1298
|
+
});
|
|
1244
1299
|
}
|
|
1245
1300
|
getNameSpace() {
|
|
1246
1301
|
if (typeof this._namespace === "function") {
|
|
@@ -1597,9 +1652,10 @@ export {
|
|
|
1597
1652
|
CacheableHooks,
|
|
1598
1653
|
CacheableMemory,
|
|
1599
1654
|
CacheableStats,
|
|
1600
|
-
|
|
1655
|
+
Keyv3 as Keyv,
|
|
1601
1656
|
KeyvCacheableMemory,
|
|
1602
1657
|
KeyvHooks,
|
|
1658
|
+
createKeyv,
|
|
1603
1659
|
shorthandToMilliseconds,
|
|
1604
1660
|
shorthandToTime,
|
|
1605
1661
|
wrap,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cacheable",
|
|
3
|
-
"version": "1.8.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.8.6",
|
|
4
|
+
"description": "High Performance Layer 1 / Layer 2 Caching with Keyv Storage",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"private": false,
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@keyv/redis": "^
|
|
25
|
-
"@types/node": "^22.
|
|
26
|
-
"@vitest/coverage-v8": "^2.1.
|
|
24
|
+
"@keyv/redis": "^4.0.2",
|
|
25
|
+
"@types/node": "^22.10.2",
|
|
26
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
27
27
|
"lru-cache": "^11.0.2",
|
|
28
28
|
"rimraf": "^6.0.1",
|
|
29
29
|
"tsup": "^8.3.5",
|
|
30
|
-
"typescript": "^5.
|
|
31
|
-
"vitest": "^2.1.
|
|
32
|
-
"xo": "^0.
|
|
30
|
+
"typescript": "^5.7.2",
|
|
31
|
+
"vitest": "^2.1.8",
|
|
32
|
+
"xo": "^0.60.0"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"hookified": "^1.5.
|
|
35
|
+
"hookified": "^1.5.1",
|
|
36
36
|
"keyv": "^5.2.1"
|
|
37
37
|
},
|
|
38
38
|
"keywords": [
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
],
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "rimraf ./dist && tsup src/index.ts --format cjs,esm --dts --clean",
|
|
70
|
+
"prepublish": "pnpm build",
|
|
70
71
|
"test": "xo --fix && vitest run --coverage",
|
|
71
72
|
"test:ci": "xo && vitest run",
|
|
72
73
|
"clean": "rimraf ./dist ./coverage ./node_modules"
|