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 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: 60 * 60 * 1000, // 1 hour
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, expiration }`.
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 = 0;
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._ttl = options.ttl;
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._ttl = value;
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
- expires = Date.now() + (ttl ?? this._ttl);
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._ttl = options.ttl;
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._ttl = ttl;
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
- await this._primary.set(key, result, this._ttl);
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
- await this._primary.set(key, secondaryResult[i], this._ttl);
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
- set(key: string, value: any, ttl?: number): void;
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
- set(key: string, value: any, ttl?: number): void;
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 = 0;
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._ttl = options.ttl;
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._ttl = value;
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
- expires = Date.now() + (ttl ?? this._ttl);
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._ttl = options.ttl;
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._ttl = ttl;
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
- await this._primary.set(key, result, this._ttl);
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
- await this._primary.set(key, secondaryResult[i], this._ttl);
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cacheable",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "Simple Caching Engine using Keyv",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",