cacheable 1.7.0 → 1.8.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
@@ -36,6 +36,7 @@
36
36
  * [Cacheable Statistics (Instance Only)](#cacheable-statistics-instance-only)
37
37
  * [API](#api)
38
38
  * [CacheableMemory - In-Memory Cache](#cacheablememory---in-memory-cache)
39
+ * [Wrap / Memoization for Sync and Async Functions](#wrap--memoization-for-sync-and-async-functions)
39
40
  * [How to Contribute](#how-to-contribute)
40
41
  * [License and Copyright](#license-and-copyright)
41
42
 
@@ -218,12 +219,13 @@ _This does not enable statistics for your layer 2 cache as that is a distributed
218
219
  * `delete(key)`: Deletes a value from the cache.
219
220
  * `deleteMany([keys])`: Deletes multiple values from the cache.
220
221
  * `clear()`: Clears the cache stores. Be careful with this as it will clear both layer 1 and layer 2.
221
- * `wrap(function, options)`: Wraps a function in a cache. (coming soon)
222
+ * `wrap(function, WrapOptions)`: Wraps an `async` function in a cache.
222
223
  * `disconnect()`: Disconnects from the cache stores.
223
224
  * `onHook(hook, callback)`: Sets a hook.
224
225
  * `removeHook(hook)`: Removes a hook.
225
226
  * `on(event, callback)`: Listens for an event.
226
227
  * `removeListener(event, callback)`: Removes a listener.
228
+ * `hash(object: any, algorithm = 'sha256'): string`: Hashes an object with the algorithm. Default is `sha256`.
227
229
  * `primary`: The primary store for the cache (layer 1) defaults to in-memory by Keyv.
228
230
  * `secondary`: The secondary store for the cache (layer 2) usually a persistent cache by Keyv.
229
231
  * `nonBlocking`: If the secondary store is non-blocking. Default is `false`.
@@ -261,17 +263,53 @@ By default we use lazy expiration deletion which means on `get` and `getMany` ty
261
263
  ### CacheableMemory API
262
264
 
263
265
  * `set(key, value, ttl?)`: Sets a value in the cache.
266
+ * `setMany([{key, value, ttl?}])`: Sets multiple values in the cache from `CachableItem`.
264
267
  * `get(key)`: Gets a value from the cache.
268
+ * `getMany([keys])`: Gets multiple values from the cache.
269
+ * `getRaw(key)`: Gets a value from the cache as `CacheableStoreItem`.
270
+ * `getManyRaw([keys])`: Gets multiple values from the cache as `CacheableStoreItem`.
265
271
  * `has(key)`: Checks if a value exists in the cache.
266
272
  * `delete(key)`: Deletes a value from the cache.
273
+ * `deleteMany([keys])`: Deletes multiple values from the cache.
274
+ * `take(key)`: Takes a value from the cache and deletes it.
275
+ * `takeMany([keys])`: Takes multiple values from the cache and deletes them.
276
+ * `wrap(function, WrapSyncOptions)`: Wraps a `sync` function in a cache.
267
277
  * `clear()`: Clears the cache.
268
278
  * `size()`: The number of keys in the cache.
269
279
  * `keys()`: The keys in the cache.
270
- * `items()`: The items in the cache as `{ key, value, expires? }`.
280
+ * `items()`: The items in the cache as `CacheableStoreItem` example `{ key, value, expires? }`.
271
281
  * `checkExpired()`: Checks for expired keys in the cache. This is used by the `checkInterval` property.
272
282
  * `startIntervalCheck()`: Starts the interval check for expired keys if `checkInterval` is above 0 ms.
273
283
  * `stopIntervalCheck()`: Stops the interval check for expired keys.
284
+ * `hash(object: any, algorithm = 'sha256'): string`: Hashes an object with the algorithm. Default is `sha256`.
285
+
286
+ ## Wrap / Memoization for Sync and Async Functions
287
+
288
+ `Cacheable` and `CacheableMemory` has a feature called `wrap` that allows you to wrap a function in a cache. This is useful for memoization and caching the results of a function. You can wrap a `sync` or `async` function in a cache. Here is an example of how to use the `wrap` function:
289
+
290
+ ```javascript
291
+ import { Cacheable } from 'cacheable';
292
+ const asyncFunction = async (value: number) => {
293
+ return value * 2;
294
+ };
295
+
296
+ const cache = new Cacheable();
297
+ const wrappedFunction = cache.wrap(asyncFunction, { ttl: '1h' });
298
+ ```
299
+
300
+ In this example we are wrapping an `async` function in a cache with a `ttl` of `1 hour`. This will cache the result of the function for `1 hour` and then expire the value. You can also wrap a `sync` function in a cache:
301
+
302
+ ```javascript
303
+ import { CacheableMemory } from 'cacheable';
304
+ const syncFunction = (value: number) => {
305
+ return value * 2;
306
+ };
307
+
308
+ const cache = new CacheableMemory();
309
+ const wrappedFunction = cache.wrap(syncFunction, { ttl: '1h' });
310
+ ```
274
311
 
312
+ In this example we are wrapping a `sync` function in a cache with a `ttl` of `1 hour`. This will cache the result of the function for `1 hour` and then expire the value.
275
313
 
276
314
  ## How to Contribute
277
315
 
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -25,9 +35,13 @@ __export(src_exports, {
25
35
  CacheableHooks: () => CacheableHooks,
26
36
  CacheableMemory: () => CacheableMemory,
27
37
  CacheableStats: () => CacheableStats,
38
+ Keyv: () => import_keyv2.Keyv,
28
39
  KeyvCacheableMemory: () => KeyvCacheableMemory,
40
+ KeyvHooks: () => import_keyv2.KeyvHooks,
29
41
  shorthandToMilliseconds: () => shorthandToMilliseconds,
30
- shorthandToTime: () => shorthandToTime
42
+ shorthandToTime: () => shorthandToTime,
43
+ wrap: () => wrap,
44
+ wrapSync: () => wrapSync
31
45
  });
32
46
  module.exports = __toCommonJS(src_exports);
33
47
  var import_keyv = require("keyv");
@@ -100,6 +114,32 @@ var shorthandToTime = (shorthand, fromDate) => {
100
114
  return fromDate.getTime() + milliseconds;
101
115
  };
102
116
 
117
+ // src/wrap.ts
118
+ function wrapSync(function_, options) {
119
+ const { ttl, key, cache } = options;
120
+ return function(...arguments_) {
121
+ const cacheKey = key ?? cache.hash(arguments_);
122
+ let value = cache.get(cacheKey);
123
+ if (value === void 0) {
124
+ value = function_(...arguments_);
125
+ cache.set(cacheKey, value, ttl);
126
+ }
127
+ return value;
128
+ };
129
+ }
130
+ function wrap(function_, options) {
131
+ const { ttl, key, cache } = options;
132
+ return async function(...arguments_) {
133
+ const cacheKey = key ?? cache.hash(arguments_);
134
+ let value = await cache.get(cacheKey);
135
+ if (value === void 0) {
136
+ value = await function_(...arguments_);
137
+ await cache.set(cacheKey, value, ttl);
138
+ }
139
+ return value;
140
+ };
141
+ }
142
+
103
143
  // src/memory-lru.ts
104
144
  var ListNode = class {
105
145
  // eslint-disable-next-line @typescript-eslint/parameter-properties
@@ -173,6 +213,18 @@ var DoublyLinkedList = class {
173
213
  }
174
214
  };
175
215
 
216
+ // src/hash.ts
217
+ var crypto = __toESM(require("crypto"), 1);
218
+ function hash(object, algorithm = "sha256") {
219
+ const objectString = JSON.stringify(object);
220
+ if (!crypto.getHashes().includes(algorithm)) {
221
+ throw new Error(`Unsupported hash algorithm: '${algorithm}'`);
222
+ }
223
+ const hasher = crypto.createHash(algorithm);
224
+ hasher.update(objectString);
225
+ return hasher.digest("hex");
226
+ }
227
+
176
228
  // src/memory.ts
177
229
  var CacheableMemory = class {
178
230
  _hashCache = /* @__PURE__ */ new Map();
@@ -262,6 +314,13 @@ var CacheableMemory = class {
262
314
  }
263
315
  return this.clone(item.value);
264
316
  }
317
+ getMany(keys) {
318
+ const result = new Array();
319
+ for (const key of keys) {
320
+ result.push(this.get(key));
321
+ }
322
+ return result;
323
+ }
265
324
  getRaw(key) {
266
325
  const store = this.getStore(key);
267
326
  const item = store.get(key);
@@ -275,6 +334,13 @@ var CacheableMemory = class {
275
334
  this.lruMoveToFront(key);
276
335
  return item;
277
336
  }
337
+ getManyRaw(keys) {
338
+ const result = new Array();
339
+ for (const key of keys) {
340
+ result.push(this.getRaw(key));
341
+ }
342
+ return result;
343
+ }
278
344
  set(key, value, ttl) {
279
345
  const store = this.getStore(key);
280
346
  let expires;
@@ -305,6 +371,11 @@ var CacheableMemory = class {
305
371
  expires
306
372
  });
307
373
  }
374
+ setMany(items) {
375
+ for (const item of items) {
376
+ this.set(item.key, item.value, item.ttl);
377
+ }
378
+ }
308
379
  has(key) {
309
380
  const item = this.get(key);
310
381
  return Boolean(item);
@@ -317,10 +388,22 @@ var CacheableMemory = class {
317
388
  this.delete(key);
318
389
  return item;
319
390
  }
391
+ takeMany(keys) {
392
+ const result = new Array();
393
+ for (const key of keys) {
394
+ result.push(this.take(key));
395
+ }
396
+ return result;
397
+ }
320
398
  delete(key) {
321
399
  const store = this.getStore(key);
322
400
  store.delete(key);
323
401
  }
402
+ deleteMany(keys) {
403
+ for (const key of keys) {
404
+ this.delete(key);
405
+ }
406
+ }
324
407
  clear() {
325
408
  this._hash0.clear();
326
409
  this._hash1.clear();
@@ -339,12 +422,12 @@ var CacheableMemory = class {
339
422
  if (cacheHashNumber) {
340
423
  return cacheHashNumber;
341
424
  }
342
- let hash = 0;
425
+ let hash2 = 0;
343
426
  const primeMultiplier = 31;
344
427
  for (let i = 0; i < key.length; i++) {
345
- hash = hash * primeMultiplier + key.charCodeAt(i);
428
+ hash2 = hash2 * primeMultiplier + key.charCodeAt(i);
346
429
  }
347
- const result = Math.abs(hash) % 10;
430
+ const result = Math.abs(hash2) % 10;
348
431
  this._hashCache.set(key, result);
349
432
  return result;
350
433
  }
@@ -435,6 +518,17 @@ var CacheableMemory = class {
435
518
  this._interval = 0;
436
519
  this._checkInterval = 0;
437
520
  }
521
+ hash(object, algorithm = "sha256") {
522
+ return hash(object, algorithm);
523
+ }
524
+ wrap(function_, options = {}) {
525
+ const wrapOptions = {
526
+ ttl: options.ttl,
527
+ key: options.key,
528
+ cache: this
529
+ };
530
+ return wrapSync(function_, wrapOptions);
531
+ }
438
532
  isPrimitive(value) {
439
533
  const result = false;
440
534
  if (value === null || value === void 0) {
@@ -483,32 +577,30 @@ var KeyvCacheableMemory = class {
483
577
  }
484
578
  return void 0;
485
579
  }
486
- set(key, value, ttl) {
580
+ async getMany(keys) {
581
+ const result = this._cache.getMany(keys);
582
+ return result;
583
+ }
584
+ async set(key, value, ttl) {
487
585
  this._cache.set(key, value, ttl);
488
586
  }
587
+ async setMany(values) {
588
+ this._cache.setMany(values);
589
+ }
489
590
  async delete(key) {
490
591
  this._cache.delete(key);
491
592
  return true;
492
593
  }
594
+ async deleteMany(key) {
595
+ this._cache.deleteMany(key);
596
+ return true;
597
+ }
493
598
  async clear() {
494
599
  this._cache.clear();
495
600
  }
496
601
  async has(key) {
497
602
  return this._cache.has(key);
498
603
  }
499
- async getMany(keys) {
500
- const result = [];
501
- for (const key of keys) {
502
- result.push(this._cache.get(key));
503
- }
504
- return result;
505
- }
506
- async deleteMany(key) {
507
- for (const k of key) {
508
- this._cache.delete(k);
509
- }
510
- return true;
511
- }
512
604
  on(event, listener) {
513
605
  return this;
514
606
  }
@@ -690,6 +782,7 @@ var CacheableStats = class {
690
782
  };
691
783
 
692
784
  // src/index.ts
785
+ var import_keyv2 = require("keyv");
693
786
  var CacheableHooks = /* @__PURE__ */ ((CacheableHooks2) => {
694
787
  CacheableHooks2["BEFORE_SET"] = "BEFORE_SET";
695
788
  CacheableHooks2["AFTER_SET"] = "AFTER_SET";
@@ -985,6 +1078,17 @@ var Cacheable = class extends import_hookified.Hookified {
985
1078
  }
986
1079
  await (this._nonBlocking ? Promise.race(promises) : Promise.all(promises));
987
1080
  }
1081
+ wrap(function_, options = {}) {
1082
+ const wrapOptions = {
1083
+ ttl: options.ttl,
1084
+ key: options.key,
1085
+ cache: this
1086
+ };
1087
+ return wrap(function_, wrapOptions);
1088
+ }
1089
+ hash(object, algorithm = "sha256") {
1090
+ return hash(object, algorithm);
1091
+ }
988
1092
  async deleteManyKeyv(keyv, keys) {
989
1093
  const promises = [];
990
1094
  for (const key of keys) {
@@ -1026,7 +1130,11 @@ var Cacheable = class extends import_hookified.Hookified {
1026
1130
  CacheableHooks,
1027
1131
  CacheableMemory,
1028
1132
  CacheableStats,
1133
+ Keyv,
1029
1134
  KeyvCacheableMemory,
1135
+ KeyvHooks,
1030
1136
  shorthandToMilliseconds,
1031
- shorthandToTime
1137
+ shorthandToTime,
1138
+ wrap,
1139
+ wrapSync
1032
1140
  });
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { KeyvStoreAdapter, StoredData, Keyv } from 'keyv';
2
+ export { Keyv, KeyvHooks, KeyvOptions, KeyvStoreAdapter } from 'keyv';
2
3
  import { Hookified } from 'hookified';
3
4
 
4
5
  type CacheableOptions$1 = {
@@ -46,17 +47,23 @@ declare class CacheableStats {
46
47
  resetStoreValues(): void;
47
48
  }
48
49
 
49
- type CacheableMemoryOptions = {
50
+ type CacheableItem = {
51
+ key: string;
52
+ value: any;
50
53
  ttl?: number | string;
51
- useClone?: boolean;
52
- lruSize?: number;
53
- checkInterval?: number;
54
54
  };
55
- type CacheableItem$1 = {
55
+ type CacheableStoreItem = {
56
56
  key: string;
57
57
  value: any;
58
58
  expires?: number;
59
59
  };
60
+
61
+ type CacheableMemoryOptions = {
62
+ ttl?: number | string;
63
+ useClone?: boolean;
64
+ lruSize?: number;
65
+ checkInterval?: number;
66
+ };
60
67
  declare class CacheableMemory {
61
68
  private readonly _hashCache;
62
69
  private readonly _hash0;
@@ -86,13 +93,18 @@ declare class CacheableMemory {
86
93
  set checkInterval(value: number);
87
94
  get size(): number;
88
95
  get keys(): IterableIterator<string>;
89
- get items(): IterableIterator<CacheableItem$1>;
90
- get<T>(key: string): any;
91
- getRaw(key: string): CacheableItem$1 | undefined;
96
+ get items(): IterableIterator<CacheableStoreItem>;
97
+ get<T>(key: string): T | undefined;
98
+ getMany<T>(keys: string[]): T[];
99
+ getRaw(key: string): CacheableStoreItem | undefined;
100
+ getManyRaw(keys: string[]): Array<CacheableStoreItem | undefined>;
92
101
  set(key: string, value: any, ttl?: number | string): void;
102
+ setMany(items: CacheableItem[]): void;
93
103
  has(key: string): boolean;
94
104
  take<T>(key: string): any;
105
+ takeMany<T>(keys: string[]): any[];
95
106
  delete(key: string): void;
107
+ deleteMany(keys: string[]): void;
96
108
  clear(): void;
97
109
  hashKey(key: string): number;
98
110
  getStore(key: string): Map<string, any>;
@@ -103,6 +115,11 @@ declare class CacheableMemory {
103
115
  checkExpiration(): void;
104
116
  startIntervalCheck(): void;
105
117
  stopIntervalCheck(): void;
118
+ hash(object: any, algorithm?: string): string;
119
+ wrap<T>(function_: (...arguments_: any[]) => T, options?: {
120
+ ttl?: number;
121
+ key?: string;
122
+ }): (...arguments_: any[]) => T;
106
123
  private isPrimitive;
107
124
  private concatStores;
108
125
  private setTtl;
@@ -114,18 +131,37 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
114
131
  private readonly _cache;
115
132
  constructor(options?: CacheableMemoryOptions);
116
133
  get<Value>(key: string): Promise<StoredData<Value> | undefined>;
117
- set(key: string, value: any, ttl?: number): void;
134
+ getMany<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;
135
+ set(key: string, value: any, ttl?: number): Promise<void>;
136
+ setMany(values: Array<{
137
+ key: string;
138
+ value: any;
139
+ ttl?: number;
140
+ }>): Promise<void>;
118
141
  delete(key: string): Promise<boolean>;
142
+ deleteMany?(key: string[]): Promise<boolean>;
119
143
  clear(): Promise<void>;
120
144
  has?(key: string): Promise<boolean>;
121
- getMany?<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;
122
- deleteMany?(key: string[]): Promise<boolean>;
123
145
  on(event: string, listener: (...arguments_: any[]) => void): this;
124
146
  }
125
147
 
126
148
  declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
127
149
  declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
128
150
 
151
+ type WrapOptions = {
152
+ ttl?: number | string;
153
+ key?: string;
154
+ cache: Cacheable;
155
+ };
156
+ type WrapSyncOptions = {
157
+ ttl?: number | string;
158
+ key?: string;
159
+ cache: CacheableMemory;
160
+ };
161
+ type AnyFunction = (...arguments_: any[]) => any;
162
+ declare function wrapSync<T>(function_: AnyFunction, options: WrapSyncOptions): AnyFunction;
163
+ declare function wrap<T>(function_: AnyFunction, options: WrapOptions): AnyFunction;
164
+
129
165
  declare enum CacheableHooks {
130
166
  BEFORE_SET = "BEFORE_SET",
131
167
  AFTER_SET = "AFTER_SET",
@@ -139,11 +175,6 @@ declare enum CacheableHooks {
139
175
  declare enum CacheableEvents {
140
176
  ERROR = "error"
141
177
  }
142
- type CacheableItem = {
143
- key: string;
144
- value: unknown;
145
- ttl?: number | string;
146
- };
147
178
  type CacheableOptions = {
148
179
  primary?: Keyv | KeyvStoreAdapter;
149
180
  secondary?: Keyv | KeyvStoreAdapter;
@@ -171,7 +202,7 @@ declare class Cacheable extends Hookified {
171
202
  setSecondary(secondary: Keyv | KeyvStoreAdapter): void;
172
203
  get<T>(key: string): Promise<T | undefined>;
173
204
  getMany<T>(keys: string[]): Promise<Array<T | undefined>>;
174
- set<T>(key: string, value: T, ttl?: number): Promise<boolean>;
205
+ set<T>(key: string, value: T, ttl?: number | string): Promise<boolean>;
175
206
  setMany(items: CacheableItem[]): Promise<boolean>;
176
207
  take<T>(key: string): Promise<T | undefined>;
177
208
  takeMany<T>(keys: string[]): Promise<Array<T | undefined>>;
@@ -181,10 +212,15 @@ declare class Cacheable extends Hookified {
181
212
  deleteMany(keys: string[]): Promise<boolean>;
182
213
  clear(): Promise<void>;
183
214
  disconnect(): Promise<void>;
215
+ wrap<T>(function_: (...arguments_: any[]) => T, options?: {
216
+ ttl?: number;
217
+ key?: string;
218
+ }): (...arguments_: any[]) => T;
219
+ hash(object: any, algorithm?: string): string;
184
220
  private deleteManyKeyv;
185
221
  private setManyKeyv;
186
222
  private hasManyKeyv;
187
223
  private setTtl;
188
224
  }
189
225
 
190
- export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory, shorthandToMilliseconds, shorthandToTime };
226
+ export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory, type WrapOptions, type WrapSyncOptions, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { KeyvStoreAdapter, StoredData, Keyv } from 'keyv';
2
+ export { Keyv, KeyvHooks, KeyvOptions, KeyvStoreAdapter } from 'keyv';
2
3
  import { Hookified } from 'hookified';
3
4
 
4
5
  type CacheableOptions$1 = {
@@ -46,17 +47,23 @@ declare class CacheableStats {
46
47
  resetStoreValues(): void;
47
48
  }
48
49
 
49
- type CacheableMemoryOptions = {
50
+ type CacheableItem = {
51
+ key: string;
52
+ value: any;
50
53
  ttl?: number | string;
51
- useClone?: boolean;
52
- lruSize?: number;
53
- checkInterval?: number;
54
54
  };
55
- type CacheableItem$1 = {
55
+ type CacheableStoreItem = {
56
56
  key: string;
57
57
  value: any;
58
58
  expires?: number;
59
59
  };
60
+
61
+ type CacheableMemoryOptions = {
62
+ ttl?: number | string;
63
+ useClone?: boolean;
64
+ lruSize?: number;
65
+ checkInterval?: number;
66
+ };
60
67
  declare class CacheableMemory {
61
68
  private readonly _hashCache;
62
69
  private readonly _hash0;
@@ -86,13 +93,18 @@ declare class CacheableMemory {
86
93
  set checkInterval(value: number);
87
94
  get size(): number;
88
95
  get keys(): IterableIterator<string>;
89
- get items(): IterableIterator<CacheableItem$1>;
90
- get<T>(key: string): any;
91
- getRaw(key: string): CacheableItem$1 | undefined;
96
+ get items(): IterableIterator<CacheableStoreItem>;
97
+ get<T>(key: string): T | undefined;
98
+ getMany<T>(keys: string[]): T[];
99
+ getRaw(key: string): CacheableStoreItem | undefined;
100
+ getManyRaw(keys: string[]): Array<CacheableStoreItem | undefined>;
92
101
  set(key: string, value: any, ttl?: number | string): void;
102
+ setMany(items: CacheableItem[]): void;
93
103
  has(key: string): boolean;
94
104
  take<T>(key: string): any;
105
+ takeMany<T>(keys: string[]): any[];
95
106
  delete(key: string): void;
107
+ deleteMany(keys: string[]): void;
96
108
  clear(): void;
97
109
  hashKey(key: string): number;
98
110
  getStore(key: string): Map<string, any>;
@@ -103,6 +115,11 @@ declare class CacheableMemory {
103
115
  checkExpiration(): void;
104
116
  startIntervalCheck(): void;
105
117
  stopIntervalCheck(): void;
118
+ hash(object: any, algorithm?: string): string;
119
+ wrap<T>(function_: (...arguments_: any[]) => T, options?: {
120
+ ttl?: number;
121
+ key?: string;
122
+ }): (...arguments_: any[]) => T;
106
123
  private isPrimitive;
107
124
  private concatStores;
108
125
  private setTtl;
@@ -114,18 +131,37 @@ declare class KeyvCacheableMemory implements KeyvStoreAdapter {
114
131
  private readonly _cache;
115
132
  constructor(options?: CacheableMemoryOptions);
116
133
  get<Value>(key: string): Promise<StoredData<Value> | undefined>;
117
- set(key: string, value: any, ttl?: number): void;
134
+ getMany<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;
135
+ set(key: string, value: any, ttl?: number): Promise<void>;
136
+ setMany(values: Array<{
137
+ key: string;
138
+ value: any;
139
+ ttl?: number;
140
+ }>): Promise<void>;
118
141
  delete(key: string): Promise<boolean>;
142
+ deleteMany?(key: string[]): Promise<boolean>;
119
143
  clear(): Promise<void>;
120
144
  has?(key: string): Promise<boolean>;
121
- getMany?<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;
122
- deleteMany?(key: string[]): Promise<boolean>;
123
145
  on(event: string, listener: (...arguments_: any[]) => void): this;
124
146
  }
125
147
 
126
148
  declare const shorthandToMilliseconds: (shorthand?: string | number) => number | undefined;
127
149
  declare const shorthandToTime: (shorthand?: string | number, fromDate?: Date) => number;
128
150
 
151
+ type WrapOptions = {
152
+ ttl?: number | string;
153
+ key?: string;
154
+ cache: Cacheable;
155
+ };
156
+ type WrapSyncOptions = {
157
+ ttl?: number | string;
158
+ key?: string;
159
+ cache: CacheableMemory;
160
+ };
161
+ type AnyFunction = (...arguments_: any[]) => any;
162
+ declare function wrapSync<T>(function_: AnyFunction, options: WrapSyncOptions): AnyFunction;
163
+ declare function wrap<T>(function_: AnyFunction, options: WrapOptions): AnyFunction;
164
+
129
165
  declare enum CacheableHooks {
130
166
  BEFORE_SET = "BEFORE_SET",
131
167
  AFTER_SET = "AFTER_SET",
@@ -139,11 +175,6 @@ declare enum CacheableHooks {
139
175
  declare enum CacheableEvents {
140
176
  ERROR = "error"
141
177
  }
142
- type CacheableItem = {
143
- key: string;
144
- value: unknown;
145
- ttl?: number | string;
146
- };
147
178
  type CacheableOptions = {
148
179
  primary?: Keyv | KeyvStoreAdapter;
149
180
  secondary?: Keyv | KeyvStoreAdapter;
@@ -171,7 +202,7 @@ declare class Cacheable extends Hookified {
171
202
  setSecondary(secondary: Keyv | KeyvStoreAdapter): void;
172
203
  get<T>(key: string): Promise<T | undefined>;
173
204
  getMany<T>(keys: string[]): Promise<Array<T | undefined>>;
174
- set<T>(key: string, value: T, ttl?: number): Promise<boolean>;
205
+ set<T>(key: string, value: T, ttl?: number | string): Promise<boolean>;
175
206
  setMany(items: CacheableItem[]): Promise<boolean>;
176
207
  take<T>(key: string): Promise<T | undefined>;
177
208
  takeMany<T>(keys: string[]): Promise<Array<T | undefined>>;
@@ -181,10 +212,15 @@ declare class Cacheable extends Hookified {
181
212
  deleteMany(keys: string[]): Promise<boolean>;
182
213
  clear(): Promise<void>;
183
214
  disconnect(): Promise<void>;
215
+ wrap<T>(function_: (...arguments_: any[]) => T, options?: {
216
+ ttl?: number;
217
+ key?: string;
218
+ }): (...arguments_: any[]) => T;
219
+ hash(object: any, algorithm?: string): string;
184
220
  private deleteManyKeyv;
185
221
  private setManyKeyv;
186
222
  private hasManyKeyv;
187
223
  private setTtl;
188
224
  }
189
225
 
190
- export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory, shorthandToMilliseconds, shorthandToTime };
226
+ export { Cacheable, CacheableEvents, CacheableHooks, type CacheableItem, CacheableMemory, type CacheableOptions, CacheableStats, KeyvCacheableMemory, type WrapOptions, type WrapSyncOptions, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync };
package/dist/index.js CHANGED
@@ -69,6 +69,32 @@ var shorthandToTime = (shorthand, fromDate) => {
69
69
  return fromDate.getTime() + milliseconds;
70
70
  };
71
71
 
72
+ // src/wrap.ts
73
+ function wrapSync(function_, options) {
74
+ const { ttl, key, cache } = options;
75
+ return function(...arguments_) {
76
+ const cacheKey = key ?? cache.hash(arguments_);
77
+ let value = cache.get(cacheKey);
78
+ if (value === void 0) {
79
+ value = function_(...arguments_);
80
+ cache.set(cacheKey, value, ttl);
81
+ }
82
+ return value;
83
+ };
84
+ }
85
+ function wrap(function_, options) {
86
+ const { ttl, key, cache } = options;
87
+ return async function(...arguments_) {
88
+ const cacheKey = key ?? cache.hash(arguments_);
89
+ let value = await cache.get(cacheKey);
90
+ if (value === void 0) {
91
+ value = await function_(...arguments_);
92
+ await cache.set(cacheKey, value, ttl);
93
+ }
94
+ return value;
95
+ };
96
+ }
97
+
72
98
  // src/memory-lru.ts
73
99
  var ListNode = class {
74
100
  // eslint-disable-next-line @typescript-eslint/parameter-properties
@@ -142,6 +168,18 @@ var DoublyLinkedList = class {
142
168
  }
143
169
  };
144
170
 
171
+ // src/hash.ts
172
+ import * as crypto from "node:crypto";
173
+ function hash(object, algorithm = "sha256") {
174
+ const objectString = JSON.stringify(object);
175
+ if (!crypto.getHashes().includes(algorithm)) {
176
+ throw new Error(`Unsupported hash algorithm: '${algorithm}'`);
177
+ }
178
+ const hasher = crypto.createHash(algorithm);
179
+ hasher.update(objectString);
180
+ return hasher.digest("hex");
181
+ }
182
+
145
183
  // src/memory.ts
146
184
  var CacheableMemory = class {
147
185
  _hashCache = /* @__PURE__ */ new Map();
@@ -231,6 +269,13 @@ var CacheableMemory = class {
231
269
  }
232
270
  return this.clone(item.value);
233
271
  }
272
+ getMany(keys) {
273
+ const result = new Array();
274
+ for (const key of keys) {
275
+ result.push(this.get(key));
276
+ }
277
+ return result;
278
+ }
234
279
  getRaw(key) {
235
280
  const store = this.getStore(key);
236
281
  const item = store.get(key);
@@ -244,6 +289,13 @@ var CacheableMemory = class {
244
289
  this.lruMoveToFront(key);
245
290
  return item;
246
291
  }
292
+ getManyRaw(keys) {
293
+ const result = new Array();
294
+ for (const key of keys) {
295
+ result.push(this.getRaw(key));
296
+ }
297
+ return result;
298
+ }
247
299
  set(key, value, ttl) {
248
300
  const store = this.getStore(key);
249
301
  let expires;
@@ -274,6 +326,11 @@ var CacheableMemory = class {
274
326
  expires
275
327
  });
276
328
  }
329
+ setMany(items) {
330
+ for (const item of items) {
331
+ this.set(item.key, item.value, item.ttl);
332
+ }
333
+ }
277
334
  has(key) {
278
335
  const item = this.get(key);
279
336
  return Boolean(item);
@@ -286,10 +343,22 @@ var CacheableMemory = class {
286
343
  this.delete(key);
287
344
  return item;
288
345
  }
346
+ takeMany(keys) {
347
+ const result = new Array();
348
+ for (const key of keys) {
349
+ result.push(this.take(key));
350
+ }
351
+ return result;
352
+ }
289
353
  delete(key) {
290
354
  const store = this.getStore(key);
291
355
  store.delete(key);
292
356
  }
357
+ deleteMany(keys) {
358
+ for (const key of keys) {
359
+ this.delete(key);
360
+ }
361
+ }
293
362
  clear() {
294
363
  this._hash0.clear();
295
364
  this._hash1.clear();
@@ -308,12 +377,12 @@ var CacheableMemory = class {
308
377
  if (cacheHashNumber) {
309
378
  return cacheHashNumber;
310
379
  }
311
- let hash = 0;
380
+ let hash2 = 0;
312
381
  const primeMultiplier = 31;
313
382
  for (let i = 0; i < key.length; i++) {
314
- hash = hash * primeMultiplier + key.charCodeAt(i);
383
+ hash2 = hash2 * primeMultiplier + key.charCodeAt(i);
315
384
  }
316
- const result = Math.abs(hash) % 10;
385
+ const result = Math.abs(hash2) % 10;
317
386
  this._hashCache.set(key, result);
318
387
  return result;
319
388
  }
@@ -404,6 +473,17 @@ var CacheableMemory = class {
404
473
  this._interval = 0;
405
474
  this._checkInterval = 0;
406
475
  }
476
+ hash(object, algorithm = "sha256") {
477
+ return hash(object, algorithm);
478
+ }
479
+ wrap(function_, options = {}) {
480
+ const wrapOptions = {
481
+ ttl: options.ttl,
482
+ key: options.key,
483
+ cache: this
484
+ };
485
+ return wrapSync(function_, wrapOptions);
486
+ }
407
487
  isPrimitive(value) {
408
488
  const result = false;
409
489
  if (value === null || value === void 0) {
@@ -452,32 +532,30 @@ var KeyvCacheableMemory = class {
452
532
  }
453
533
  return void 0;
454
534
  }
455
- set(key, value, ttl) {
535
+ async getMany(keys) {
536
+ const result = this._cache.getMany(keys);
537
+ return result;
538
+ }
539
+ async set(key, value, ttl) {
456
540
  this._cache.set(key, value, ttl);
457
541
  }
542
+ async setMany(values) {
543
+ this._cache.setMany(values);
544
+ }
458
545
  async delete(key) {
459
546
  this._cache.delete(key);
460
547
  return true;
461
548
  }
549
+ async deleteMany(key) {
550
+ this._cache.deleteMany(key);
551
+ return true;
552
+ }
462
553
  async clear() {
463
554
  this._cache.clear();
464
555
  }
465
556
  async has(key) {
466
557
  return this._cache.has(key);
467
558
  }
468
- async getMany(keys) {
469
- const result = [];
470
- for (const key of keys) {
471
- result.push(this._cache.get(key));
472
- }
473
- return result;
474
- }
475
- async deleteMany(key) {
476
- for (const k of key) {
477
- this._cache.delete(k);
478
- }
479
- return true;
480
- }
481
559
  on(event, listener) {
482
560
  return this;
483
561
  }
@@ -659,6 +737,10 @@ var CacheableStats = class {
659
737
  };
660
738
 
661
739
  // src/index.ts
740
+ import {
741
+ KeyvHooks,
742
+ Keyv as Keyv2
743
+ } from "keyv";
662
744
  var CacheableHooks = /* @__PURE__ */ ((CacheableHooks2) => {
663
745
  CacheableHooks2["BEFORE_SET"] = "BEFORE_SET";
664
746
  CacheableHooks2["AFTER_SET"] = "AFTER_SET";
@@ -954,6 +1036,17 @@ var Cacheable = class extends Hookified {
954
1036
  }
955
1037
  await (this._nonBlocking ? Promise.race(promises) : Promise.all(promises));
956
1038
  }
1039
+ wrap(function_, options = {}) {
1040
+ const wrapOptions = {
1041
+ ttl: options.ttl,
1042
+ key: options.key,
1043
+ cache: this
1044
+ };
1045
+ return wrap(function_, wrapOptions);
1046
+ }
1047
+ hash(object, algorithm = "sha256") {
1048
+ return hash(object, algorithm);
1049
+ }
957
1050
  async deleteManyKeyv(keyv, keys) {
958
1051
  const promises = [];
959
1052
  for (const key of keys) {
@@ -994,7 +1087,11 @@ export {
994
1087
  CacheableHooks,
995
1088
  CacheableMemory,
996
1089
  CacheableStats,
1090
+ Keyv2 as Keyv,
997
1091
  KeyvCacheableMemory,
1092
+ KeyvHooks,
998
1093
  shorthandToMilliseconds,
999
- shorthandToTime
1094
+ shorthandToTime,
1095
+ wrap,
1096
+ wrapSync
1000
1097
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cacheable",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Simple Caching Engine using Keyv",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -18,7 +18,7 @@
18
18
  "private": false,
19
19
  "devDependencies": {
20
20
  "@keyv/redis": "^3.0.1",
21
- "@types/node": "^22.6.1",
21
+ "@types/node": "^22.7.4",
22
22
  "@vitest/coverage-v8": "^2.1.1",
23
23
  "lru-cache": "^11.0.1",
24
24
  "rimraf": "^6.0.1",