cacheable 1.6.1 → 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 -3
- package/dist/index.cjs +120 -14
- package/dist/index.d.cts +15 -9
- package/dist/index.d.ts +15 -9
- package/dist/index.js +117 -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,7 +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.
|
|
215
|
-
* `items()`: The items in the cache as `{ key, value,
|
|
270
|
+
* `items()`: The items in the cache as `{ key, value, expires? }`.
|
|
216
271
|
* `checkExpired()`: Checks for expired keys in the cache. This is used by the `checkInterval` property.
|
|
217
272
|
* `startIntervalCheck()`: Starts the interval check for expired keys if `checkInterval` is above 0 ms.
|
|
218
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;
|
|
@@ -193,11 +262,27 @@ var CacheableMemory = class {
|
|
|
193
262
|
}
|
|
194
263
|
return this.clone(item.value);
|
|
195
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
|
+
}
|
|
196
278
|
set(key, value, ttl) {
|
|
197
279
|
const store = this.getStore(key);
|
|
198
280
|
let expires;
|
|
199
|
-
if (ttl !== void 0 || this._ttl !== 0) {
|
|
200
|
-
|
|
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
|
+
}
|
|
201
286
|
}
|
|
202
287
|
if (this._lruSize > 0) {
|
|
203
288
|
if (store.has(key)) {
|
|
@@ -364,6 +449,15 @@ var CacheableMemory = class {
|
|
|
364
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]);
|
|
365
450
|
return result;
|
|
366
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
|
+
}
|
|
367
461
|
};
|
|
368
462
|
|
|
369
463
|
// src/keyv-memory.ts
|
|
@@ -384,7 +478,6 @@ var KeyvCacheableMemory = class {
|
|
|
384
478
|
}
|
|
385
479
|
async get(key) {
|
|
386
480
|
const result = this._cache.get(key);
|
|
387
|
-
console.log("result", result);
|
|
388
481
|
if (result) {
|
|
389
482
|
return result;
|
|
390
483
|
}
|
|
@@ -633,7 +726,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
633
726
|
this._stats.enabled = options.stats;
|
|
634
727
|
}
|
|
635
728
|
if (options?.ttl) {
|
|
636
|
-
this.
|
|
729
|
+
this.setTtl(options.ttl);
|
|
637
730
|
}
|
|
638
731
|
}
|
|
639
732
|
get stats() {
|
|
@@ -661,7 +754,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
661
754
|
return this._ttl;
|
|
662
755
|
}
|
|
663
756
|
set ttl(ttl) {
|
|
664
|
-
this.
|
|
757
|
+
this.setTtl(ttl);
|
|
665
758
|
}
|
|
666
759
|
setPrimary(primary) {
|
|
667
760
|
this._primary = primary instanceof import_keyv.Keyv ? primary : new import_keyv.Keyv(primary);
|
|
@@ -677,7 +770,8 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
677
770
|
if (!result && this._secondary) {
|
|
678
771
|
result = await this._secondary.get(key);
|
|
679
772
|
if (result) {
|
|
680
|
-
|
|
773
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
774
|
+
await this._primary.set(key, result, finalTtl);
|
|
681
775
|
}
|
|
682
776
|
}
|
|
683
777
|
await this.hook("AFTER_GET" /* AFTER_GET */, { key, result });
|
|
@@ -710,7 +804,8 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
710
804
|
for (const [i, key] of keys.entries()) {
|
|
711
805
|
if (!result[i] && secondaryResult[i]) {
|
|
712
806
|
result[i] = secondaryResult[i];
|
|
713
|
-
|
|
807
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
808
|
+
await this._primary.set(key, secondaryResult[i], finalTtl);
|
|
714
809
|
}
|
|
715
810
|
}
|
|
716
811
|
}
|
|
@@ -732,7 +827,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
732
827
|
}
|
|
733
828
|
async set(key, value, ttl) {
|
|
734
829
|
let result = false;
|
|
735
|
-
const finalTtl = ttl ?? this._ttl;
|
|
830
|
+
const finalTtl = shorthandToMilliseconds(ttl ?? this._ttl);
|
|
736
831
|
try {
|
|
737
832
|
const item = { key, value, ttl: finalTtl };
|
|
738
833
|
await this.hook("BEFORE_SET" /* BEFORE_SET */, item);
|
|
@@ -901,7 +996,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
901
996
|
async setManyKeyv(keyv, items) {
|
|
902
997
|
const promises = [];
|
|
903
998
|
for (const item of items) {
|
|
904
|
-
const finalTtl = item.ttl ?? this._ttl;
|
|
999
|
+
const finalTtl = shorthandToMilliseconds(item.ttl ?? this._ttl);
|
|
905
1000
|
promises.push(keyv.set(item.key, item.value, finalTtl));
|
|
906
1001
|
}
|
|
907
1002
|
await Promise.all(promises);
|
|
@@ -914,6 +1009,15 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
914
1009
|
}
|
|
915
1010
|
return Promise.all(promises);
|
|
916
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
|
+
}
|
|
917
1021
|
};
|
|
918
1022
|
// Annotate the CommonJS export names for ESM import in node:
|
|
919
1023
|
0 && (module.exports = {
|
|
@@ -922,5 +1026,7 @@ var Cacheable = class extends import_hookified.Hookified {
|
|
|
922
1026
|
CacheableHooks,
|
|
923
1027
|
CacheableMemory,
|
|
924
1028
|
CacheableStats,
|
|
925
|
-
KeyvCacheableMemory
|
|
1029
|
+
KeyvCacheableMemory,
|
|
1030
|
+
shorthandToMilliseconds,
|
|
1031
|
+
shorthandToTime
|
|
926
1032
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -47,7 +47,7 @@ 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;
|
|
@@ -76,8 +76,8 @@ declare class CacheableMemory {
|
|
|
76
76
|
private _checkInterval;
|
|
77
77
|
private _interval;
|
|
78
78
|
constructor(options?: CacheableMemoryOptions);
|
|
79
|
-
get ttl(): number;
|
|
80
|
-
set ttl(value: number);
|
|
79
|
+
get ttl(): number | string | undefined;
|
|
80
|
+
set ttl(value: number | string | undefined);
|
|
81
81
|
get useClone(): boolean;
|
|
82
82
|
set useClone(value: boolean);
|
|
83
83
|
get lruSize(): number;
|
|
@@ -88,7 +88,8 @@ declare class CacheableMemory {
|
|
|
88
88
|
get keys(): IterableIterator<string>;
|
|
89
89
|
get items(): IterableIterator<CacheableItem$1>;
|
|
90
90
|
get<T>(key: string): any;
|
|
91
|
-
|
|
91
|
+
getRaw(key: string): CacheableItem$1 | undefined;
|
|
92
|
+
set(key: string, value: any, ttl?: number | string): void;
|
|
92
93
|
has(key: string): boolean;
|
|
93
94
|
take<T>(key: string): any;
|
|
94
95
|
delete(key: string): void;
|
|
@@ -104,6 +105,7 @@ declare class CacheableMemory {
|
|
|
104
105
|
stopIntervalCheck(): void;
|
|
105
106
|
private isPrimitive;
|
|
106
107
|
private concatStores;
|
|
108
|
+
private setTtl;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
@@ -121,6 +123,9 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
|
121
123
|
on(event: string, listener: (...arguments_: any[]) => void): this;
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
|
|
127
|
+
declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
|
|
128
|
+
|
|
124
129
|
declare enum CacheableHooks {
|
|
125
130
|
BEFORE_SET = "BEFORE_SET",
|
|
126
131
|
AFTER_SET = "AFTER_SET",
|
|
@@ -137,14 +142,14 @@ declare enum CacheableEvents {
|
|
|
137
142
|
type CacheableItem = {
|
|
138
143
|
key: string;
|
|
139
144
|
value: unknown;
|
|
140
|
-
ttl?: number;
|
|
145
|
+
ttl?: number | string;
|
|
141
146
|
};
|
|
142
147
|
type CacheableOptions = {
|
|
143
148
|
primary?: Keyv | KeyvStoreAdapter;
|
|
144
149
|
secondary?: Keyv | KeyvStoreAdapter;
|
|
145
150
|
stats?: boolean;
|
|
146
151
|
nonBlocking?: boolean;
|
|
147
|
-
ttl?: number;
|
|
152
|
+
ttl?: number | string;
|
|
148
153
|
};
|
|
149
154
|
declare class Cacheable extends Hookified {
|
|
150
155
|
private _primary;
|
|
@@ -160,8 +165,8 @@ declare class Cacheable extends Hookified {
|
|
|
160
165
|
set secondary(secondary: Keyv | undefined);
|
|
161
166
|
get nonBlocking(): boolean;
|
|
162
167
|
set nonBlocking(nonBlocking: boolean);
|
|
163
|
-
get ttl(): number | undefined;
|
|
164
|
-
set ttl(ttl: number | undefined);
|
|
168
|
+
get ttl(): number | string | undefined;
|
|
169
|
+
set ttl(ttl: number | string | undefined);
|
|
165
170
|
setPrimary(primary: Keyv | KeyvStoreAdapter): void;
|
|
166
171
|
setSecondary(secondary: Keyv | KeyvStoreAdapter): void;
|
|
167
172
|
get<T>(key: string): Promise<T | undefined>;
|
|
@@ -179,6 +184,7 @@ declare class Cacheable extends Hookified {
|
|
|
179
184
|
private deleteManyKeyv;
|
|
180
185
|
private setManyKeyv;
|
|
181
186
|
private hasManyKeyv;
|
|
187
|
+
private setTtl;
|
|
182
188
|
}
|
|
183
189
|
|
|
184
|
-
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,7 +47,7 @@ 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;
|
|
@@ -76,8 +76,8 @@ declare class CacheableMemory {
|
|
|
76
76
|
private _checkInterval;
|
|
77
77
|
private _interval;
|
|
78
78
|
constructor(options?: CacheableMemoryOptions);
|
|
79
|
-
get ttl(): number;
|
|
80
|
-
set ttl(value: number);
|
|
79
|
+
get ttl(): number | string | undefined;
|
|
80
|
+
set ttl(value: number | string | undefined);
|
|
81
81
|
get useClone(): boolean;
|
|
82
82
|
set useClone(value: boolean);
|
|
83
83
|
get lruSize(): number;
|
|
@@ -88,7 +88,8 @@ declare class CacheableMemory {
|
|
|
88
88
|
get keys(): IterableIterator<string>;
|
|
89
89
|
get items(): IterableIterator<CacheableItem$1>;
|
|
90
90
|
get<T>(key: string): any;
|
|
91
|
-
|
|
91
|
+
getRaw(key: string): CacheableItem$1 | undefined;
|
|
92
|
+
set(key: string, value: any, ttl?: number | string): void;
|
|
92
93
|
has(key: string): boolean;
|
|
93
94
|
take<T>(key: string): any;
|
|
94
95
|
delete(key: string): void;
|
|
@@ -104,6 +105,7 @@ declare class CacheableMemory {
|
|
|
104
105
|
stopIntervalCheck(): void;
|
|
105
106
|
private isPrimitive;
|
|
106
107
|
private concatStores;
|
|
108
|
+
private setTtl;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
@@ -121,6 +123,9 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
|
|
|
121
123
|
on(event: string, listener: (...arguments_: any[]) => void): this;
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
|
|
127
|
+
declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
|
|
128
|
+
|
|
124
129
|
declare enum CacheableHooks {
|
|
125
130
|
BEFORE_SET = "BEFORE_SET",
|
|
126
131
|
AFTER_SET = "AFTER_SET",
|
|
@@ -137,14 +142,14 @@ declare enum CacheableEvents {
|
|
|
137
142
|
type CacheableItem = {
|
|
138
143
|
key: string;
|
|
139
144
|
value: unknown;
|
|
140
|
-
ttl?: number;
|
|
145
|
+
ttl?: number | string;
|
|
141
146
|
};
|
|
142
147
|
type CacheableOptions = {
|
|
143
148
|
primary?: Keyv | KeyvStoreAdapter;
|
|
144
149
|
secondary?: Keyv | KeyvStoreAdapter;
|
|
145
150
|
stats?: boolean;
|
|
146
151
|
nonBlocking?: boolean;
|
|
147
|
-
ttl?: number;
|
|
152
|
+
ttl?: number | string;
|
|
148
153
|
};
|
|
149
154
|
declare class Cacheable extends Hookified {
|
|
150
155
|
private _primary;
|
|
@@ -160,8 +165,8 @@ declare class Cacheable extends Hookified {
|
|
|
160
165
|
set secondary(secondary: Keyv | undefined);
|
|
161
166
|
get nonBlocking(): boolean;
|
|
162
167
|
set nonBlocking(nonBlocking: boolean);
|
|
163
|
-
get ttl(): number | undefined;
|
|
164
|
-
set ttl(ttl: number | undefined);
|
|
168
|
+
get ttl(): number | string | undefined;
|
|
169
|
+
set ttl(ttl: number | string | undefined);
|
|
165
170
|
setPrimary(primary: Keyv | KeyvStoreAdapter): void;
|
|
166
171
|
setSecondary(secondary: Keyv | KeyvStoreAdapter): void;
|
|
167
172
|
get<T>(key: string): Promise<T | undefined>;
|
|
@@ -179,6 +184,7 @@ declare class Cacheable extends Hookified {
|
|
|
179
184
|
private deleteManyKeyv;
|
|
180
185
|
private setManyKeyv;
|
|
181
186
|
private hasManyKeyv;
|
|
187
|
+
private setTtl;
|
|
182
188
|
}
|
|
183
189
|
|
|
184
|
-
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;
|
|
@@ -164,11 +231,27 @@ var CacheableMemory = class {
|
|
|
164
231
|
}
|
|
165
232
|
return this.clone(item.value);
|
|
166
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
|
+
}
|
|
167
247
|
set(key, value, ttl) {
|
|
168
248
|
const store = this.getStore(key);
|
|
169
249
|
let expires;
|
|
170
|
-
if (ttl !== void 0 || this._ttl !== 0) {
|
|
171
|
-
|
|
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
|
+
}
|
|
172
255
|
}
|
|
173
256
|
if (this._lruSize > 0) {
|
|
174
257
|
if (store.has(key)) {
|
|
@@ -335,6 +418,15 @@ var CacheableMemory = class {
|
|
|
335
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]);
|
|
336
419
|
return result;
|
|
337
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
|
+
}
|
|
338
430
|
};
|
|
339
431
|
|
|
340
432
|
// src/keyv-memory.ts
|
|
@@ -355,7 +447,6 @@ var KeyvCacheableMemory = class {
|
|
|
355
447
|
}
|
|
356
448
|
async get(key) {
|
|
357
449
|
const result = this._cache.get(key);
|
|
358
|
-
console.log("result", result);
|
|
359
450
|
if (result) {
|
|
360
451
|
return result;
|
|
361
452
|
}
|
|
@@ -604,7 +695,7 @@ var Cacheable = class extends Hookified {
|
|
|
604
695
|
this._stats.enabled = options.stats;
|
|
605
696
|
}
|
|
606
697
|
if (options?.ttl) {
|
|
607
|
-
this.
|
|
698
|
+
this.setTtl(options.ttl);
|
|
608
699
|
}
|
|
609
700
|
}
|
|
610
701
|
get stats() {
|
|
@@ -632,7 +723,7 @@ var Cacheable = class extends Hookified {
|
|
|
632
723
|
return this._ttl;
|
|
633
724
|
}
|
|
634
725
|
set ttl(ttl) {
|
|
635
|
-
this.
|
|
726
|
+
this.setTtl(ttl);
|
|
636
727
|
}
|
|
637
728
|
setPrimary(primary) {
|
|
638
729
|
this._primary = primary instanceof Keyv ? primary : new Keyv(primary);
|
|
@@ -648,7 +739,8 @@ var Cacheable = class extends Hookified {
|
|
|
648
739
|
if (!result && this._secondary) {
|
|
649
740
|
result = await this._secondary.get(key);
|
|
650
741
|
if (result) {
|
|
651
|
-
|
|
742
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
743
|
+
await this._primary.set(key, result, finalTtl);
|
|
652
744
|
}
|
|
653
745
|
}
|
|
654
746
|
await this.hook("AFTER_GET" /* AFTER_GET */, { key, result });
|
|
@@ -681,7 +773,8 @@ var Cacheable = class extends Hookified {
|
|
|
681
773
|
for (const [i, key] of keys.entries()) {
|
|
682
774
|
if (!result[i] && secondaryResult[i]) {
|
|
683
775
|
result[i] = secondaryResult[i];
|
|
684
|
-
|
|
776
|
+
const finalTtl = shorthandToMilliseconds(this._ttl);
|
|
777
|
+
await this._primary.set(key, secondaryResult[i], finalTtl);
|
|
685
778
|
}
|
|
686
779
|
}
|
|
687
780
|
}
|
|
@@ -703,7 +796,7 @@ var Cacheable = class extends Hookified {
|
|
|
703
796
|
}
|
|
704
797
|
async set(key, value, ttl) {
|
|
705
798
|
let result = false;
|
|
706
|
-
const finalTtl = ttl ?? this._ttl;
|
|
799
|
+
const finalTtl = shorthandToMilliseconds(ttl ?? this._ttl);
|
|
707
800
|
try {
|
|
708
801
|
const item = { key, value, ttl: finalTtl };
|
|
709
802
|
await this.hook("BEFORE_SET" /* BEFORE_SET */, item);
|
|
@@ -872,7 +965,7 @@ var Cacheable = class extends Hookified {
|
|
|
872
965
|
async setManyKeyv(keyv, items) {
|
|
873
966
|
const promises = [];
|
|
874
967
|
for (const item of items) {
|
|
875
|
-
const finalTtl = item.ttl ?? this._ttl;
|
|
968
|
+
const finalTtl = shorthandToMilliseconds(item.ttl ?? this._ttl);
|
|
876
969
|
promises.push(keyv.set(item.key, item.value, finalTtl));
|
|
877
970
|
}
|
|
878
971
|
await Promise.all(promises);
|
|
@@ -885,6 +978,15 @@ var Cacheable = class extends Hookified {
|
|
|
885
978
|
}
|
|
886
979
|
return Promise.all(promises);
|
|
887
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
|
+
}
|
|
888
990
|
};
|
|
889
991
|
export {
|
|
890
992
|
Cacheable,
|
|
@@ -892,5 +994,7 @@ export {
|
|
|
892
994
|
CacheableHooks,
|
|
893
995
|
CacheableMemory,
|
|
894
996
|
CacheableStats,
|
|
895
|
-
KeyvCacheableMemory
|
|
997
|
+
KeyvCacheableMemory,
|
|
998
|
+
shorthandToMilliseconds,
|
|
999
|
+
shorthandToTime
|
|
896
1000
|
};
|