cacheable 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -2
- package/dist/index.cjs +123 -14
- package/dist/index.d.cts +21 -9
- package/dist/index.d.ts +21 -9
- package/dist/index.js +120 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,10 +19,26 @@
|
|
|
19
19
|
* Resilient to failures with try/catch and offline
|
|
20
20
|
* Hooks and Events to extend functionality
|
|
21
21
|
* Comprehensive testing and code coverage
|
|
22
|
+
* Shorthand for ttl in milliseconds `(1m = 60000) (1h = 3600000) (1d = 86400000)`
|
|
22
23
|
* Distributed Caching Sync via Pub/Sub (coming soon)
|
|
23
24
|
* ESM and CommonJS support with TypeScript
|
|
24
25
|
* Maintained and supported regularly
|
|
25
26
|
|
|
27
|
+
## Table of Contents
|
|
28
|
+
* [Getting Started](#getting-started)
|
|
29
|
+
* [Basic Usage](#basic-usage)
|
|
30
|
+
* [Hooks and Events](#hooks-and-events)
|
|
31
|
+
* [Storage Tiering and Caching](#storage-tiering-and-caching)
|
|
32
|
+
* [Shorthand for Time to Live (ttl)](#shorthand-for-time-to-live-ttl)
|
|
33
|
+
* [Non-Blocking Operations](#non-blocking-operations)
|
|
34
|
+
* [CacheSync - Distributed Updates](#cachesync---distributed-updates)
|
|
35
|
+
* [Cacheable Options](#cacheable-options)
|
|
36
|
+
* [Cacheable Statistics (Instance Only)](#cacheable-statistics-instance-only)
|
|
37
|
+
* [API](#api)
|
|
38
|
+
* [CacheableMemory - In-Memory Cache](#cacheablememory---in-memory-cache)
|
|
39
|
+
* [How to Contribute](#how-to-contribute)
|
|
40
|
+
* [License and Copyright](#license-and-copyright)
|
|
41
|
+
|
|
26
42
|
## Getting Started
|
|
27
43
|
|
|
28
44
|
`cacheable` is primarily used as an extension to you caching engine with a robust storage backend [Keyv](https://keyv.org), Memonization (Wrap), Hooks, Events, and Statistics.
|
|
@@ -99,6 +115,44 @@ cacheable.onHook(CacheableHooks.BEFORE_SET, (data) => {
|
|
|
99
115
|
* `Deleting Data`: Deletes the value from the primary store and secondary store at the same time waiting for both to respond.
|
|
100
116
|
* `Clearing Data`: Clears the primary store and secondary store at the same time waiting for both to respond.
|
|
101
117
|
|
|
118
|
+
# Shorthand for Time to Live (ttl)
|
|
119
|
+
|
|
120
|
+
By default `Cacheable` and `CacheableMemory` the `ttl` is in milliseconds but you can use shorthand for the time to live. Here are the following shorthand values:
|
|
121
|
+
|
|
122
|
+
* `ms`: Milliseconds such as (1ms = 1)
|
|
123
|
+
* `s`: Seconds such as (1s = 1000)
|
|
124
|
+
* `m`: Minutes such as (1m = 60000)
|
|
125
|
+
* `h` or `hr`: Hours such as (1h = 3600000)
|
|
126
|
+
* `d`: Days such as (1d = 86400000)
|
|
127
|
+
|
|
128
|
+
Here is an example of how to use the shorthand for the `ttl`:
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
import { Cacheable } from 'cacheable';
|
|
132
|
+
const cache = new Cacheable({ ttl: '15m' }); //sets the default ttl to 15 minutes (900000 ms)
|
|
133
|
+
cache.set('key', 'value', '1h'); //sets the ttl to 1 hour (3600000 ms) and overrides the default
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
if you want to disable the `ttl` you can set it to `0` or `undefined`:
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
import { Cacheable } from 'cacheable';
|
|
140
|
+
const cache = new Cacheable({ ttl: 0 }); //sets the default ttl to 0 which is disabled
|
|
141
|
+
cache.set('key', 'value', 0); //sets the ttl to 0 which is disabled
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
If you set the ttl to anything below `0` or `undefined` it will disable the ttl for the cache and the value that returns will be `undefined`. With no ttl set the value will be stored `indefinitely`.
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
import { Cacheable } from 'cacheable';
|
|
148
|
+
const cache = new Cacheable({ ttl: 0 }); //sets the default ttl to 0 which is disabled
|
|
149
|
+
console.log(cache.ttl); // undefined
|
|
150
|
+
cache.ttl = '1h'; // sets the default ttl to 1 hour (3600000 ms)
|
|
151
|
+
console.log(cache.ttl); // '1h'
|
|
152
|
+
cache.ttl = -1; // sets the default ttl to 0 which is disabled
|
|
153
|
+
console.log(cache.ttl); // undefined
|
|
154
|
+
```
|
|
155
|
+
|
|
102
156
|
## Non-Blocking Operations
|
|
103
157
|
|
|
104
158
|
If you want your layer 2 (secondary) store to be non-blocking you can set the `nonBlocking` property to `true` in the options. This will make the secondary store non-blocking and will not wait for the secondary store to respond on `setting data`, `deleting data`, or `clearing data`. This is useful if you want to have a faster response time and not wait for the secondary store to respond.
|
|
@@ -131,6 +185,7 @@ The following options are available for you to configure `cacheable`:
|
|
|
131
185
|
* `secondary`: The secondary store for the cache (layer 2) usually a persistent cache by Keyv.
|
|
132
186
|
* `nonBlocking`: If the secondary store is non-blocking. Default is `false`.
|
|
133
187
|
* `stats`: To enable statistics for this instance. Default is `false`.
|
|
188
|
+
* `ttl`: The default time to live for the cache in milliseconds. Default is `undefined` which is disabled.
|
|
134
189
|
|
|
135
190
|
## Cacheable Statistics (Instance Only)
|
|
136
191
|
|
|
@@ -181,7 +236,7 @@ _This does not enable statistics for your layer 2 cache as that is a distributed
|
|
|
181
236
|
```javascript
|
|
182
237
|
import { CacheableMemory } from 'cacheable';
|
|
183
238
|
const options = {
|
|
184
|
-
ttl:
|
|
239
|
+
ttl: '1h', // 1 hour
|
|
185
240
|
useClones: true, // use clones for the values (default is true)
|
|
186
241
|
lruSize: 1000, // the size of the LRU cache (default is 0 which is unlimited)
|
|
187
242
|
}
|
|
@@ -198,7 +253,7 @@ By default we use lazy expiration deletion which means on `get` and `getMany` ty
|
|
|
198
253
|
|
|
199
254
|
### CacheableMemory Options
|
|
200
255
|
|
|
201
|
-
* `ttl`: The time to live for the cache in milliseconds.
|
|
256
|
+
* `ttl`: The time to live for the cache in milliseconds. Default is `undefined` which is means indefinitely.
|
|
202
257
|
* `useClones`: If the cache should use clones for the values. Default is `true`.
|
|
203
258
|
* `lruSize`: The size of the LRU cache. Default is `0` which is unlimited.
|
|
204
259
|
* `checkInterval`: The interval to check for expired keys in milliseconds. Default is `0` which is disabled.
|
|
@@ -212,6 +267,7 @@ By default we use lazy expiration deletion which means on `get` and `getMany` ty
|
|
|
212
267
|
* `clear()`: Clears the cache.
|
|
213
268
|
* `size()`: The number of keys in the cache.
|
|
214
269
|
* `keys()`: The keys in the cache.
|
|
270
|
+
* `items()`: The items in the cache as `{ key, value, expires? }`.
|
|
215
271
|
* `checkExpired()`: Checks for expired keys in the cache. This is used by the `checkInterval` property.
|
|
216
272
|
* `startIntervalCheck()`: Starts the interval check for expired keys if `checkInterval` is above 0 ms.
|
|
217
273
|
* `stopIntervalCheck()`: Stops the interval check for expired keys.
|
package/dist/index.cjs
CHANGED
|
@@ -25,12 +25,81 @@ __export(src_exports, {
|
|
|
25
25
|
CacheableHooks: () => CacheableHooks,
|
|
26
26
|
CacheableMemory: () => CacheableMemory,
|
|
27
27
|
CacheableStats: () => CacheableStats,
|
|
28
|
-
KeyvCacheableMemory: () => KeyvCacheableMemory
|
|
28
|
+
KeyvCacheableMemory: () => KeyvCacheableMemory,
|
|
29
|
+
shorthandToMilliseconds: () => shorthandToMilliseconds,
|
|
30
|
+
shorthandToTime: () => shorthandToTime
|
|
29
31
|
});
|
|
30
32
|
module.exports = __toCommonJS(src_exports);
|
|
31
33
|
var import_keyv = require("keyv");
|
|
32
34
|
var import_hookified = require("hookified");
|
|
33
35
|
|
|
36
|
+
// src/shorthand-time.ts
|
|
37
|
+
var shorthandToMilliseconds = (shorthand) => {
|
|
38
|
+
let milliseconds;
|
|
39
|
+
if (shorthand === void 0) {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
if (typeof shorthand === "number") {
|
|
43
|
+
milliseconds = shorthand;
|
|
44
|
+
} else if (typeof shorthand === "string") {
|
|
45
|
+
shorthand = shorthand.trim();
|
|
46
|
+
if (Number.isNaN(Number(shorthand))) {
|
|
47
|
+
const match = /^([\d.]+)\s*(ms|s|m|h|hr|d)$/i.exec(shorthand);
|
|
48
|
+
if (!match) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Unsupported time format: "${shorthand}". Use 'ms', 's', 'm', 'h', 'hr', or 'd'.`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const [, value, unit] = match;
|
|
54
|
+
const numericValue = Number.parseFloat(value);
|
|
55
|
+
const unitLower = unit.toLowerCase();
|
|
56
|
+
switch (unitLower) {
|
|
57
|
+
case "ms": {
|
|
58
|
+
milliseconds = numericValue;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case "s": {
|
|
62
|
+
milliseconds = numericValue * 1e3;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case "m": {
|
|
66
|
+
milliseconds = numericValue * 1e3 * 60;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case "h": {
|
|
70
|
+
milliseconds = numericValue * 1e3 * 60 * 60;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case "hr": {
|
|
74
|
+
milliseconds = numericValue * 1e3 * 60 * 60;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case "d": {
|
|
78
|
+
milliseconds = numericValue * 1e3 * 60 * 60 * 24;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
/* c8 ignore next 3 */
|
|
82
|
+
default: {
|
|
83
|
+
milliseconds = Number(shorthand);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
milliseconds = Number(shorthand);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
throw new TypeError("Time must be a string or a number.");
|
|
91
|
+
}
|
|
92
|
+
return milliseconds;
|
|
93
|
+
};
|
|
94
|
+
var shorthandToTime = (shorthand, fromDate) => {
|
|
95
|
+
fromDate ||= /* @__PURE__ */ new Date();
|
|
96
|
+
const milliseconds = shorthandToMilliseconds(shorthand);
|
|
97
|
+
if (milliseconds === void 0) {
|
|
98
|
+
return fromDate.getTime();
|
|
99
|
+
}
|
|
100
|
+
return fromDate.getTime() + milliseconds;
|
|
101
|
+
};
|
|
102
|
+
|
|
34
103
|
// src/memory-lru.ts
|
|
35
104
|
var ListNode = class {
|
|
36
105
|
// eslint-disable-next-line @typescript-eslint/parameter-properties
|
|
@@ -118,7 +187,7 @@ var CacheableMemory = class {
|
|
|
118
187
|
_hash8 = /* @__PURE__ */ new Map();
|
|
119
188
|
_hash9 = /* @__PURE__ */ new Map();
|
|
120
189
|
_lru = new DoublyLinkedList();
|
|
121
|
-
_ttl
|
|
190
|
+
_ttl;
|
|
122
191
|
// Turned off by default
|
|
123
192
|
_useClone = true;
|
|
124
193
|
// Turned on by default
|
|
@@ -130,7 +199,7 @@ var CacheableMemory = class {
|
|
|
130
199
|
// Turned off by default
|
|
131
200
|
constructor(options) {
|
|
132
201
|
if (options?.ttl) {
|
|
133
|
-
this.
|
|
202
|
+
this.setTtl(options.ttl);
|
|
134
203
|
}
|
|
135
204
|
if (options?.useClone !== void 0) {
|
|
136
205
|
this._useClone = options.useClone;
|
|
@@ -147,7 +216,7 @@ var CacheableMemory = class {
|
|
|
147
216
|
return this._ttl;
|
|
148
217
|
}
|
|
149
218
|
set ttl(value) {
|
|
150
|
-
this.
|
|
219
|
+
this.setTtl(value);
|
|
151
220
|
}
|
|
152
221
|
get useClone() {
|
|
153
222
|
return this._useClone;
|
|
@@ -174,6 +243,9 @@ var CacheableMemory = class {
|
|
|
174
243
|
get keys() {
|
|
175
244
|
return this.concatStores().keys();
|
|
176
245
|
}
|
|
246
|
+
get items() {
|
|
247
|
+
return this.concatStores().values();
|
|
248
|
+
}
|
|
177
249
|
get(key) {
|
|
178
250
|
const store = this.getStore(key);
|
|
179
251
|
const item = store.get(key);
|
|
@@ -190,11 +262,27 @@ var CacheableMemory = class {
|
|
|
190
262
|
}
|
|
191
263
|
return this.clone(item.value);
|
|
192
264
|
}
|
|
265
|
+
getRaw(key) {
|
|
266
|
+
const store = this.getStore(key);
|
|
267
|
+
const item = store.get(key);
|
|
268
|
+
if (!item) {
|
|
269
|
+
return void 0;
|
|
270
|
+
}
|
|
271
|
+
if (item.expires && item.expires && Date.now() > item.expires) {
|
|
272
|
+
store.delete(key);
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
this.lruMoveToFront(key);
|
|
276
|
+
return item;
|
|
277
|
+
}
|
|
193
278
|
set(key, value, ttl) {
|
|
194
279
|
const store = this.getStore(key);
|
|
195
280
|
let expires;
|
|
196
|
-
if (ttl !== void 0 || this._ttl !== 0) {
|
|
197
|
-
|
|
281
|
+
if (ttl !== void 0 || this._ttl !== void 0) {
|
|
282
|
+
const finalTtl = shorthandToTime(ttl ?? this._ttl);
|
|
283
|
+
if (finalTtl !== void 0) {
|
|
284
|
+
expires = finalTtl;
|
|
285
|
+
}
|
|
198
286
|
}
|
|
199
287
|
if (this._lruSize > 0) {
|
|
200
288
|
if (store.has(key)) {
|
|
@@ -361,6 +449,15 @@ var CacheableMemory = class {
|
|
|
361
449
|
const result = new Map([...this._hash0, ...this._hash1, ...this._hash2, ...this._hash3, ...this._hash4, ...this._hash5, ...this._hash6, ...this._hash7, ...this._hash8, ...this._hash9]);
|
|
362
450
|
return result;
|
|
363
451
|
}
|
|
452
|
+
setTtl(ttl) {
|
|
453
|
+
if (typeof ttl === "string" || ttl === void 0) {
|
|
454
|
+
this._ttl = ttl;
|
|
455
|
+
} else if (ttl > 0) {
|
|
456
|
+
this._ttl = ttl;
|
|
457
|
+
} else {
|
|
458
|
+
this._ttl = void 0;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
364
461
|
};
|
|
365
462
|
|
|
366
463
|
// src/keyv-memory.ts
|
|
@@ -381,7 +478,6 @@ var KeyvCacheableMemory = class {
|
|
|
381
478
|
}
|
|
382
479
|
async get(key) {
|
|
383
480
|
const result = this._cache.get(key);
|
|
384
|
-
console.log("result", result);
|
|
385
481
|
if (result) {
|
|
386
482
|
return result;
|
|
387
483
|
}
|
|
@@ -630,7 +726,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
630
726
|
this._stats.enabled = options.stats;
|
|
631
727
|
}
|
|
632
728
|
if (options?.ttl) {
|
|
633
|
-
this.
|
|
729
|
+
this.setTtl(options.ttl);
|
|
634
730
|
}
|
|
635
731
|
}
|
|
636
732
|
get stats() {
|
|
@@ -658,7 +754,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
658
754
|
return this._ttl;
|
|
659
755
|
}
|
|
660
756
|
set ttl(ttl) {
|
|
661
|
-
this.
|
|
757
|
+
this.setTtl(ttl);
|
|
662
758
|
}
|
|
663
759
|
setPrimary(primary) {
|
|
664
760
|
this._primary = primary instanceof import_keyv.Keyv ? primary : new import_keyv.Keyv(primary);
|
|
@@ -674,7 +770,8 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
674
770
|
if (!result && this._secondary) {
|
|
675
771
|
result = await this._secondary.get(key);
|
|
676
772
|
if (result) {
|
|
677
|
-
|
|
773
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
774
|
+
await this._primary.set(key, result, finalTtl);
|
|
678
775
|
}
|
|
679
776
|
}
|
|
680
777
|
await this.hook("AFTER_GET" /* AFTER_GET */, { key, result });
|
|
@@ -707,7 +804,8 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
707
804
|
for (const [i, key] of keys.entries()) {
|
|
708
805
|
if (!result[i] && secondaryResult[i]) {
|
|
709
806
|
result[i] = secondaryResult[i];
|
|
710
|
-
|
|
807
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
808
|
+
await this._primary.set(key, secondaryResult[i], finalTtl);
|
|
711
809
|
}
|
|
712
810
|
}
|
|
713
811
|
}
|
|
@@ -729,7 +827,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
729
827
|
}
|
|
730
828
|
async set(key, value, ttl) {
|
|
731
829
|
let result = false;
|
|
732
|
-
const finalTtl = ttl ?? this._ttl;
|
|
830
|
+
const finalTtl = shorthandToMilliseconds(ttl ?? this._ttl);
|
|
733
831
|
try {
|
|
734
832
|
const item = { key, value, ttl: finalTtl };
|
|
735
833
|
await this.hook("BEFORE_SET" /* BEFORE_SET */, item);
|
|
@@ -898,7 +996,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
898
996
|
async setManyKeyv(keyv, items) {
|
|
899
997
|
const promises = [];
|
|
900
998
|
for (const item of items) {
|
|
901
|
-
const finalTtl = item.ttl ?? this._ttl;
|
|
999
|
+
const finalTtl = shorthandToMilliseconds(item.ttl ?? this._ttl);
|
|
902
1000
|
promises.push(keyv.set(item.key, item.value, finalTtl));
|
|
903
1001
|
}
|
|
904
1002
|
await Promise.all(promises);
|
|
@@ -911,6 +1009,15 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
911
1009
|
}
|
|
912
1010
|
return Promise.all(promises);
|
|
913
1011
|
}
|
|
1012
|
+
setTtl(ttl) {
|
|
1013
|
+
if (typeof ttl === "string" || ttl === void 0) {
|
|
1014
|
+
this._ttl = ttl;
|
|
1015
|
+
} else if (ttl > 0) {
|
|
1016
|
+
this._ttl = ttl;
|
|
1017
|
+
} else {
|
|
1018
|
+
this._ttl = void 0;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
914
1021
|
};
|
|
915
1022
|
// Annotate the CommonJS export names for ESM import in node:
|
|
916
1023
|
0 && (module.exports = {
|
|
@@ -919,5 +1026,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
919
1026
|
CacheableHooks,
|
|
920
1027
|
CacheableMemory,
|
|
921
1028
|
CacheableStats,
|
|
922
|
-
KeyvCacheableMemory
|
|
1029
|
+
KeyvCacheableMemory,
|
|
1030
|
+
shorthandToMilliseconds,
|
|
1031
|
+
shorthandToTime
|
|
923
1032
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -47,11 +47,16 @@ declare class CacheableStats {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
type CacheableMemoryOptions = {
|
|
50
|
-
ttl?: number;
|
|
50
|
+
ttl?: number | string;
|
|
51
51
|
useClone?: boolean;
|
|
52
52
|
lruSize?: number;
|
|
53
53
|
checkInterval?: number;
|
|
54
54
|
};
|
|
55
|
+
type CacheableItem$1 = {
|
|
56
|
+
key: string;
|
|
57
|
+
value: any;
|
|
58
|
+
expires?: number;
|
|
59
|
+
};
|
|
55
60
|
declare class CacheableMemory {
|
|
56
61
|
private readonly _hashCache;
|
|
57
62
|
private readonly _hash0;
|
|
@@ -71,8 +76,8 @@ declare class CacheableMemory {
|
|
|
71
76
|
private _checkInterval;
|
|
72
77
|
private _interval;
|
|
73
78
|
constructor(options?: CacheableMemoryOptions);
|
|
74
|
-
get ttl(): number;
|
|
75
|
-
set ttl(value: number);
|
|
79
|
+
get ttl(): number | string | undefined;
|
|
80
|
+
set ttl(value: number | string | undefined);
|
|
76
81
|
get useClone(): boolean;
|
|
77
82
|
set useClone(value: boolean);
|
|
78
83
|
get lruSize(): number;
|
|
@@ -81,8 +86,10 @@ declare class CacheableMemory {
|
|
|
81
86
|
set checkInterval(value: number);
|
|
82
87
|
get size(): number;
|
|
83
88
|
get keys(): IterableIterator<string>;
|
|
89
|
+
get items(): IterableIterator<CacheableItem$1>;
|
|
84
90
|
get<T>(key: string): any;
|
|
85
|
-
|
|
91
|
+
getRaw(key: string): CacheableItem$1 | undefined;
|
|
92
|
+
set(key: string, value: any, ttl?: number | string): void;
|
|
86
93
|
has(key: string): boolean;
|
|
87
94
|
take<T>(key: string): any;
|
|
88
95
|
delete(key: string): void;
|
|
@@ -98,6 +105,7 @@ declare class CacheableMemory {
|
|
|
98
105
|
stopIntervalCheck(): void;
|
|
99
106
|
private isPrimitive;
|
|
100
107
|
private concatStores;
|
|
108
|
+
private setTtl;
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
@@ -115,6 +123,9 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
|
115
123
|
on(event: string, listener: (...arguments_: any[]) => void): this;
|
|
116
124
|
}
|
|
117
125
|
|
|
126
|
+
declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
|
|
127
|
+
declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
|
|
128
|
+
|
|
118
129
|
declare enum CacheableHooks {
|
|
119
130
|
BEFORE_SET = "BEFORE_SET",
|
|
120
131
|
AFTER_SET = "AFTER_SET",
|
|
@@ -131,14 +142,14 @@ declare enum CacheableEvents {
|
|
|
131
142
|
type CacheableItem = {
|
|
132
143
|
key: string;
|
|
133
144
|
value: unknown;
|
|
134
|
-
ttl?: number;
|
|
145
|
+
ttl?: number | string;
|
|
135
146
|
};
|
|
136
147
|
type CacheableOptions = {
|
|
137
148
|
primary?: Keyv | KeyvStoreAdapter;
|
|
138
149
|
secondary?: Keyv | KeyvStoreAdapter;
|
|
139
150
|
stats?: boolean;
|
|
140
151
|
nonBlocking?: boolean;
|
|
141
|
-
ttl?: number;
|
|
152
|
+
ttl?: number | string;
|
|
142
153
|
};
|
|
143
154
|
declare class Cacheable extends Hookified {
|
|
144
155
|
private _primary;
|
|
@@ -154,8 +165,8 @@ declare class Cacheable extends Hookified {
|
|
|
154
165
|
set secondary(secondary: Keyv | undefined);
|
|
155
166
|
get nonBlocking(): boolean;
|
|
156
167
|
set nonBlocking(nonBlocking: boolean);
|
|
157
|
-
get ttl(): number | undefined;
|
|
158
|
-
set ttl(ttl: number | undefined);
|
|
168
|
+
get ttl(): number | string | undefined;
|
|
169
|
+
set ttl(ttl: number | string | undefined);
|
|
159
170
|
setPrimary(primary: Keyv | KeyvStoreAdapter): void;
|
|
160
171
|
setSecondary(secondary: Keyv | KeyvStoreAdapter): void;
|
|
161
172
|
get<T>(key: string): Promise<T | undefined>;
|
|
@@ -173,6 +184,7 @@ declare class Cacheable extends Hookified {
|
|
|
173
184
|
private deleteManyKeyv;
|
|
174
185
|
private setManyKeyv;
|
|
175
186
|
private hasManyKeyv;
|
|
187
|
+
private setTtl;
|
|
176
188
|
}
|
|
177
189
|
|
|
178
|
-
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory };
|
|
190
|
+
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory, shorthandToMilliseconds, shorthandToTime };
|
package/dist/index.d.ts
CHANGED
|
@@ -47,11 +47,16 @@ declare class CacheableStats {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
type CacheableMemoryOptions = {
|
|
50
|
-
ttl?: number;
|
|
50
|
+
ttl?: number | string;
|
|
51
51
|
useClone?: boolean;
|
|
52
52
|
lruSize?: number;
|
|
53
53
|
checkInterval?: number;
|
|
54
54
|
};
|
|
55
|
+
type CacheableItem$1 = {
|
|
56
|
+
key: string;
|
|
57
|
+
value: any;
|
|
58
|
+
expires?: number;
|
|
59
|
+
};
|
|
55
60
|
declare class CacheableMemory {
|
|
56
61
|
private readonly _hashCache;
|
|
57
62
|
private readonly _hash0;
|
|
@@ -71,8 +76,8 @@ declare class CacheableMemory {
|
|
|
71
76
|
private _checkInterval;
|
|
72
77
|
private _interval;
|
|
73
78
|
constructor(options?: CacheableMemoryOptions);
|
|
74
|
-
get ttl(): number;
|
|
75
|
-
set ttl(value: number);
|
|
79
|
+
get ttl(): number | string | undefined;
|
|
80
|
+
set ttl(value: number | string | undefined);
|
|
76
81
|
get useClone(): boolean;
|
|
77
82
|
set useClone(value: boolean);
|
|
78
83
|
get lruSize(): number;
|
|
@@ -81,8 +86,10 @@ declare class CacheableMemory {
|
|
|
81
86
|
set checkInterval(value: number);
|
|
82
87
|
get size(): number;
|
|
83
88
|
get keys(): IterableIterator<string>;
|
|
89
|
+
get items(): IterableIterator<CacheableItem$1>;
|
|
84
90
|
get<T>(key: string): any;
|
|
85
|
-
|
|
91
|
+
getRaw(key: string): CacheableItem$1 | undefined;
|
|
92
|
+
set(key: string, value: any, ttl?: number | string): void;
|
|
86
93
|
has(key: string): boolean;
|
|
87
94
|
take<T>(key: string): any;
|
|
88
95
|
delete(key: string): void;
|
|
@@ -98,6 +105,7 @@ declare class CacheableMemory {
|
|
|
98
105
|
stopIntervalCheck(): void;
|
|
99
106
|
private isPrimitive;
|
|
100
107
|
private concatStores;
|
|
108
|
+
private setTtl;
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
@@ -115,6 +123,9 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
|
115
123
|
on(event: string, listener: (...arguments_: any[]) => void): this;
|
|
116
124
|
}
|
|
117
125
|
|
|
126
|
+
declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
|
|
127
|
+
declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
|
|
128
|
+
|
|
118
129
|
declare enum CacheableHooks {
|
|
119
130
|
BEFORE_SET = "BEFORE_SET",
|
|
120
131
|
AFTER_SET = "AFTER_SET",
|
|
@@ -131,14 +142,14 @@ declare enum CacheableEvents {
|
|
|
131
142
|
type CacheableItem = {
|
|
132
143
|
key: string;
|
|
133
144
|
value: unknown;
|
|
134
|
-
ttl?: number;
|
|
145
|
+
ttl?: number | string;
|
|
135
146
|
};
|
|
136
147
|
type CacheableOptions = {
|
|
137
148
|
primary?: Keyv | KeyvStoreAdapter;
|
|
138
149
|
secondary?: Keyv | KeyvStoreAdapter;
|
|
139
150
|
stats?: boolean;
|
|
140
151
|
nonBlocking?: boolean;
|
|
141
|
-
ttl?: number;
|
|
152
|
+
ttl?: number | string;
|
|
142
153
|
};
|
|
143
154
|
declare class Cacheable extends Hookified {
|
|
144
155
|
private _primary;
|
|
@@ -154,8 +165,8 @@ declare class Cacheable extends Hookified {
|
|
|
154
165
|
set secondary(secondary: Keyv | undefined);
|
|
155
166
|
get nonBlocking(): boolean;
|
|
156
167
|
set nonBlocking(nonBlocking: boolean);
|
|
157
|
-
get ttl(): number | undefined;
|
|
158
|
-
set ttl(ttl: number | undefined);
|
|
168
|
+
get ttl(): number | string | undefined;
|
|
169
|
+
set ttl(ttl: number | string | undefined);
|
|
159
170
|
setPrimary(primary: Keyv | KeyvStoreAdapter): void;
|
|
160
171
|
setSecondary(secondary: Keyv | KeyvStoreAdapter): void;
|
|
161
172
|
get<T>(key: string): Promise<T | undefined>;
|
|
@@ -173,6 +184,7 @@ declare class Cacheable extends Hookified {
|
|
|
173
184
|
private deleteManyKeyv;
|
|
174
185
|
private setManyKeyv;
|
|
175
186
|
private hasManyKeyv;
|
|
187
|
+
private setTtl;
|
|
176
188
|
}
|
|
177
189
|
|
|
178
|
-
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory };
|
|
190
|
+
export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory, shorthandToMilliseconds, shorthandToTime };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,73 @@
|
|
|
2
2
|
import { Keyv } from "keyv";
|
|
3
3
|
import { Hookified } from "hookified";
|
|
4
4
|
|
|
5
|
+
// src/shorthand-time.ts
|
|
6
|
+
var shorthandToMilliseconds = (shorthand) => {
|
|
7
|
+
let milliseconds;
|
|
8
|
+
if (shorthand === void 0) {
|
|
9
|
+
return void 0;
|
|
10
|
+
}
|
|
11
|
+
if (typeof shorthand === "number") {
|
|
12
|
+
milliseconds = shorthand;
|
|
13
|
+
} else if (typeof shorthand === "string") {
|
|
14
|
+
shorthand = shorthand.trim();
|
|
15
|
+
if (Number.isNaN(Number(shorthand))) {
|
|
16
|
+
const match = /^([\d.]+)\s*(ms|s|m|h|hr|d)$/i.exec(shorthand);
|
|
17
|
+
if (!match) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Unsupported time format: "${shorthand}". Use 'ms', 's', 'm', 'h', 'hr', or 'd'.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
const [, value, unit] = match;
|
|
23
|
+
const numericValue = Number.parseFloat(value);
|
|
24
|
+
const unitLower = unit.toLowerCase();
|
|
25
|
+
switch (unitLower) {
|
|
26
|
+
case "ms": {
|
|
27
|
+
milliseconds = numericValue;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
case "s": {
|
|
31
|
+
milliseconds = numericValue * 1e3;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
case "m": {
|
|
35
|
+
milliseconds = numericValue * 1e3 * 60;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
case "h": {
|
|
39
|
+
milliseconds = numericValue * 1e3 * 60 * 60;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "hr": {
|
|
43
|
+
milliseconds = numericValue * 1e3 * 60 * 60;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case "d": {
|
|
47
|
+
milliseconds = numericValue * 1e3 * 60 * 60 * 24;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
/* c8 ignore next 3 */
|
|
51
|
+
default: {
|
|
52
|
+
milliseconds = Number(shorthand);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
milliseconds = Number(shorthand);
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
throw new TypeError("Time must be a string or a number.");
|
|
60
|
+
}
|
|
61
|
+
return milliseconds;
|
|
62
|
+
};
|
|
63
|
+
var shorthandToTime = (shorthand, fromDate) => {
|
|
64
|
+
fromDate ||= /* @__PURE__ */ new Date();
|
|
65
|
+
const milliseconds = shorthandToMilliseconds(shorthand);
|
|
66
|
+
if (milliseconds === void 0) {
|
|
67
|
+
return fromDate.getTime();
|
|
68
|
+
}
|
|
69
|
+
return fromDate.getTime() + milliseconds;
|
|
70
|
+
};
|
|
71
|
+
|
|
5
72
|
// src/memory-lru.ts
|
|
6
73
|
var ListNode = class {
|
|
7
74
|
// eslint-disable-next-line @typescript-eslint/parameter-properties
|
|
@@ -89,7 +156,7 @@ var CacheableMemory = class {
|
|
|
89
156
|
_hash8 = /* @__PURE__ */ new Map();
|
|
90
157
|
_hash9 = /* @__PURE__ */ new Map();
|
|
91
158
|
_lru = new DoublyLinkedList();
|
|
92
|
-
_ttl
|
|
159
|
+
_ttl;
|
|
93
160
|
// Turned off by default
|
|
94
161
|
_useClone = true;
|
|
95
162
|
// Turned on by default
|
|
@@ -101,7 +168,7 @@ var CacheableMemory = class {
|
|
|
101
168
|
// Turned off by default
|
|
102
169
|
constructor(options) {
|
|
103
170
|
if (options?.ttl) {
|
|
104
|
-
this.
|
|
171
|
+
this.setTtl(options.ttl);
|
|
105
172
|
}
|
|
106
173
|
if (options?.useClone !== void 0) {
|
|
107
174
|
this._useClone = options.useClone;
|
|
@@ -118,7 +185,7 @@ var CacheableMemory = class {
|
|
|
118
185
|
return this._ttl;
|
|
119
186
|
}
|
|
120
187
|
set ttl(value) {
|
|
121
|
-
this.
|
|
188
|
+
this.setTtl(value);
|
|
122
189
|
}
|
|
123
190
|
get useClone() {
|
|
124
191
|
return this._useClone;
|
|
@@ -145,6 +212,9 @@ var CacheableMemory = class {
|
|
|
145
212
|
get keys() {
|
|
146
213
|
return this.concatStores().keys();
|
|
147
214
|
}
|
|
215
|
+
get items() {
|
|
216
|
+
return this.concatStores().values();
|
|
217
|
+
}
|
|
148
218
|
get(key) {
|
|
149
219
|
const store = this.getStore(key);
|
|
150
220
|
const item = store.get(key);
|
|
@@ -161,11 +231,27 @@ var CacheableMemory = class {
|
|
|
161
231
|
}
|
|
162
232
|
return this.clone(item.value);
|
|
163
233
|
}
|
|
234
|
+
getRaw(key) {
|
|
235
|
+
const store = this.getStore(key);
|
|
236
|
+
const item = store.get(key);
|
|
237
|
+
if (!item) {
|
|
238
|
+
return void 0;
|
|
239
|
+
}
|
|
240
|
+
if (item.expires && item.expires && Date.now() > item.expires) {
|
|
241
|
+
store.delete(key);
|
|
242
|
+
return void 0;
|
|
243
|
+
}
|
|
244
|
+
this.lruMoveToFront(key);
|
|
245
|
+
return item;
|
|
246
|
+
}
|
|
164
247
|
set(key, value, ttl) {
|
|
165
248
|
const store = this.getStore(key);
|
|
166
249
|
let expires;
|
|
167
|
-
if (ttl !== void 0 || this._ttl !== 0) {
|
|
168
|
-
|
|
250
|
+
if (ttl !== void 0 || this._ttl !== void 0) {
|
|
251
|
+
const finalTtl = shorthandToTime(ttl ?? this._ttl);
|
|
252
|
+
if (finalTtl !== void 0) {
|
|
253
|
+
expires = finalTtl;
|
|
254
|
+
}
|
|
169
255
|
}
|
|
170
256
|
if (this._lruSize > 0) {
|
|
171
257
|
if (store.has(key)) {
|
|
@@ -332,6 +418,15 @@ var CacheableMemory = class {
|
|
|
332
418
|
const result = new Map([...this._hash0, ...this._hash1, ...this._hash2, ...this._hash3, ...this._hash4, ...this._hash5, ...this._hash6, ...this._hash7, ...this._hash8, ...this._hash9]);
|
|
333
419
|
return result;
|
|
334
420
|
}
|
|
421
|
+
setTtl(ttl) {
|
|
422
|
+
if (typeof ttl === "string" || ttl === void 0) {
|
|
423
|
+
this._ttl = ttl;
|
|
424
|
+
} else if (ttl > 0) {
|
|
425
|
+
this._ttl = ttl;
|
|
426
|
+
} else {
|
|
427
|
+
this._ttl = void 0;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
335
430
|
};
|
|
336
431
|
|
|
337
432
|
// src/keyv-memory.ts
|
|
@@ -352,7 +447,6 @@ var KeyvCacheableMemory = class {
|
|
|
352
447
|
}
|
|
353
448
|
async get(key) {
|
|
354
449
|
const result = this._cache.get(key);
|
|
355
|
-
console.log("result", result);
|
|
356
450
|
if (result) {
|
|
357
451
|
return result;
|
|
358
452
|
}
|
|
@@ -601,7 +695,7 @@ var Cacheable = class extends Hookified {
|
|
|
601
695
|
this._stats.enabled = options.stats;
|
|
602
696
|
}
|
|
603
697
|
if (options?.ttl) {
|
|
604
|
-
this.
|
|
698
|
+
this.setTtl(options.ttl);
|
|
605
699
|
}
|
|
606
700
|
}
|
|
607
701
|
get stats() {
|
|
@@ -629,7 +723,7 @@ var Cacheable = class extends Hookified {
|
|
|
629
723
|
return this._ttl;
|
|
630
724
|
}
|
|
631
725
|
set ttl(ttl) {
|
|
632
|
-
this.
|
|
726
|
+
this.setTtl(ttl);
|
|
633
727
|
}
|
|
634
728
|
setPrimary(primary) {
|
|
635
729
|
this._primary = primary instanceof Keyv ? primary : new Keyv(primary);
|
|
@@ -645,7 +739,8 @@ var Cacheable = class extends Hookified {
|
|
|
645
739
|
if (!result && this._secondary) {
|
|
646
740
|
result = await this._secondary.get(key);
|
|
647
741
|
if (result) {
|
|
648
|
-
|
|
742
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
743
|
+
await this._primary.set(key, result, finalTtl);
|
|
649
744
|
}
|
|
650
745
|
}
|
|
651
746
|
await this.hook("AFTER_GET" /* AFTER_GET */, { key, result });
|
|
@@ -678,7 +773,8 @@ var Cacheable = class extends Hookified {
|
|
|
678
773
|
for (const [i, key] of keys.entries()) {
|
|
679
774
|
if (!result[i] && secondaryResult[i]) {
|
|
680
775
|
result[i] = secondaryResult[i];
|
|
681
|
-
|
|
776
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
777
|
+
await this._primary.set(key, secondaryResult[i], finalTtl);
|
|
682
778
|
}
|
|
683
779
|
}
|
|
684
780
|
}
|
|
@@ -700,7 +796,7 @@ var Cacheable = class extends Hookified {
|
|
|
700
796
|
}
|
|
701
797
|
async set(key, value, ttl) {
|
|
702
798
|
let result = false;
|
|
703
|
-
const finalTtl = ttl ?? this._ttl;
|
|
799
|
+
const finalTtl = shorthandToMilliseconds(ttl ?? this._ttl);
|
|
704
800
|
try {
|
|
705
801
|
const item = { key, value, ttl: finalTtl };
|
|
706
802
|
await this.hook("BEFORE_SET" /* BEFORE_SET */, item);
|
|
@@ -869,7 +965,7 @@ var Cacheable = class extends Hookified {
|
|
|
869
965
|
async setManyKeyv(keyv, items) {
|
|
870
966
|
const promises = [];
|
|
871
967
|
for (const item of items) {
|
|
872
|
-
const finalTtl = item.ttl ?? this._ttl;
|
|
968
|
+
const finalTtl = shorthandToMilliseconds(item.ttl ?? this._ttl);
|
|
873
969
|
promises.push(keyv.set(item.key, item.value, finalTtl));
|
|
874
970
|
}
|
|
875
971
|
await Promise.all(promises);
|
|
@@ -882,6 +978,15 @@ var Cacheable = class extends Hookified {
|
|
|
882
978
|
}
|
|
883
979
|
return Promise.all(promises);
|
|
884
980
|
}
|
|
981
|
+
setTtl(ttl) {
|
|
982
|
+
if (typeof ttl === "string" || ttl === void 0) {
|
|
983
|
+
this._ttl = ttl;
|
|
984
|
+
} else if (ttl > 0) {
|
|
985
|
+
this._ttl = ttl;
|
|
986
|
+
} else {
|
|
987
|
+
this._ttl = void 0;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
885
990
|
};
|
|
886
991
|
export {
|
|
887
992
|
Cacheable,
|
|
@@ -889,5 +994,7 @@ export {
|
|
|
889
994
|
CacheableHooks,
|
|
890
995
|
CacheableMemory,
|
|
891
996
|
CacheableStats,
|
|
892
|
-
KeyvCacheableMemory
|
|
997
|
+
KeyvCacheableMemory,
|
|
998
|
+
shorthandToMilliseconds,
|
|
999
|
+
shorthandToTime
|
|
893
1000
|
};
|