cacheable 2.1.1 → 2.2.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
@@ -32,6 +32,7 @@
32
32
  * [Storage Tiering and Caching](#storage-tiering-and-caching)
33
33
  * [TTL Propagation and Storage Tiering](#ttl-propagation-and-storage-tiering)
34
34
  * [Shorthand for Time to Live (ttl)](#shorthand-for-time-to-live-ttl)
35
+ * [Iteration on Primary and Secondary Stores](#iteration-on-primary-and-secondary-stores)
35
36
  * [Non-Blocking Operations](#non-blocking-operations)
36
37
  * [Non-Blocking with @keyv/redis](#non-blocking-with-keyvredis)
37
38
  * [CacheableSync - Distributed Updates](#cacheablesync---distributed-updates)
@@ -279,6 +280,110 @@ raws.forEach((entry, idx) => {
279
280
  });
280
281
  ```
281
282
 
283
+ ## Checking multiple keys with hasMany
284
+
285
+ The `hasMany` method allows you to efficiently check if multiple keys exist in the cache. It leverages Keyv's native `hasMany` support for optimal performance:
286
+
287
+ ```typescript
288
+ import { Cacheable } from 'cacheable';
289
+
290
+ const cache = new Cacheable();
291
+
292
+ // set some values
293
+ await cache.set('user:1', { name: 'Alice' });
294
+ await cache.set('user:2', { name: 'Bob' });
295
+
296
+ // check if multiple keys exist
297
+ const exists = await cache.hasMany(['user:1', 'user:2', 'user:3']);
298
+ console.log(exists); // [true, true, false]
299
+ ```
300
+
301
+ The `hasMany` method returns an array of booleans in the same order as the input keys. This is particularly useful when you need to verify the existence of multiple cache entries before performing batch operations.
302
+
303
+ # Iteration on Primary and Secondary Stores
304
+
305
+ The `Cacheable` class exposes both `primary` and `secondary` Keyv instances, which support iteration over their stored entries using the `iterator()` method. This allows you to access and process all keys and values in either storage layer.
306
+
307
+ **Important Notes:**
308
+ - Not all storage adapters support iteration. Always check if `iterator` exists before using it.
309
+ - The iterator automatically filters by namespace, skips expired entries (and deletes them), and deserializes values.
310
+ - **Performance Warning:** Be careful when using `iterator()` as it can cause performance issues with large datasets.
311
+
312
+ ## Basic Iteration Example
313
+
314
+ ```typescript
315
+ import { Cacheable } from 'cacheable';
316
+ import KeyvRedis from '@keyv/redis';
317
+
318
+ // Create cache with primary (in-memory) and secondary (Redis) stores
319
+ const secondary = new KeyvRedis('redis://user:pass@localhost:6379');
320
+ const cache = new Cacheable({ secondary });
321
+
322
+ // Add some data
323
+ await cache.set('user:1', { name: 'Alice', role: 'admin' });
324
+ await cache.set('user:2', { name: 'Bob', role: 'user' });
325
+ await cache.set('session:abc', { userId: '1', active: true });
326
+
327
+ // Iterate over primary store (in-memory)
328
+ console.log('Primary store contents:');
329
+ if (cache.primary.iterator) {
330
+ for await (const [key, value] of cache.primary.iterator()) {
331
+ console.log(` ${key}:`, JSON.stringify(value));
332
+ }
333
+ }
334
+
335
+ // Iterate over secondary store (Redis)
336
+ console.log('\nSecondary store contents:');
337
+ if (cache.secondary?.iterator) {
338
+ for await (const [key, value] of cache.secondary.iterator()) {
339
+ console.log(` ${key}:`, JSON.stringify(value));
340
+ }
341
+ }
342
+ ```
343
+
344
+ ## Safe Iteration Helper
345
+
346
+ Here's a recommended helper function for safe iteration that checks for store availability and iterator support:
347
+
348
+ ```typescript
349
+ import { Cacheable } from 'cacheable';
350
+ import type { Keyv } from 'keyv';
351
+
352
+ async function iterateStore(store: Keyv | undefined, storeName: string) {
353
+ if (!store) {
354
+ console.log(`${storeName} store not configured`);
355
+ return;
356
+ }
357
+
358
+ if (!store.iterator) {
359
+ console.log(`${storeName} store does not support iteration`);
360
+ return;
361
+ }
362
+
363
+ console.log(`${storeName} store entries:`);
364
+ for await (const [key, value] of store.iterator()) {
365
+ console.log(` ${key}:`, value);
366
+ }
367
+ }
368
+
369
+ // Usage
370
+ const cache = new Cacheable({ /* options */ });
371
+ await iterateStore(cache.primary, 'Primary');
372
+ await iterateStore(cache.secondary, 'Secondary');
373
+ ```
374
+
375
+ ## Storage Adapter Support
376
+
377
+ The `iterator()` method is available when:
378
+ - The store is a Map instance (has Symbol.iterator)
379
+ - The store implements an `iterator()` method (e.g., Redis, Valkey, etc.)
380
+ - The store is a supported iterable adapter
381
+
382
+ Common stores that support iteration:
383
+ - In-memory (Map-based stores)
384
+ - @keyv/redis
385
+ - @keyv/valkey
386
+ - Other Keyv adapters that implement the iterator interface
282
387
 
283
388
  # Non-Blocking Operations
284
389
 
@@ -517,7 +622,8 @@ _This does not enable statistics for your layer 2 cache as that is a distributed
517
622
  * `removeHook(hook)`: Removes a hook.
518
623
  * `on(event, callback)`: Listens for an event.
519
624
  * `removeListener(event, callback)`: Removes a listener.
520
- * `hash(object: any, algorithm = 'sha256'): string`: Hashes an object with the algorithm. Default is `sha256`.
625
+ * `hash(object: any, algorithm = 'SHA-256'): Promise<string>`: Asynchronously hashes an object with a cryptographic algorithm (SHA-256, SHA-384, SHA-512). Default is `SHA-256`.
626
+ * `hashSync(object: any, algorithm = 'djb2'): string`: Synchronously hashes an object with a non-cryptographic algorithm (djb2, fnv1, murmer, crc32). Default is `djb2`.
521
627
  * `primary`: The primary store for the cache (layer 1) defaults to in-memory by Keyv.
522
628
  * `secondary`: The secondary store for the cache (layer 2) usually a persistent cache by Keyv.
523
629
  * `namespace`: The namespace for the cache. Default is `undefined`. This will set the namespace for the primary and secondary stores.
@@ -544,7 +650,7 @@ To learn more go to [@cacheable/memory](https://cacheable.org/docs/memory/)
544
650
 
545
651
  # Wrap / Memoization for Sync and Async Functions
546
652
 
547
- `Cacheable` and `CacheableMemory` has a feature called `wrap` that comes from [@cacheable/memoize](https://cacheable.org/docs/memoize/) and 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:
653
+ `Cacheable` and `CacheableMemory` has a feature called `wrap` that comes from [@cacheable/utils](https://cacheable.org/docs/utils/) and 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:
548
654
 
549
655
  ```javascript
550
656
  import { Cacheable } from 'cacheable';
@@ -637,11 +743,11 @@ If you would like to generate your own key for the wrapped function you can set
637
743
 
638
744
  We will pass in the `function` that is being wrapped, the `arguments` passed to the function, and the `options` used to wrap the function. You can then use these to generate a custom key for the cache.
639
745
 
640
- To learn more visit [@cacheable/memoize](https://cacheable.org/docs/memoize/)
746
+ To learn more visit [@cacheable/utils](https://cacheable.org/docs/utils/)
641
747
 
642
748
  # Get Or Set Memoization Function
643
749
 
644
- The `getOrSet` method that comes from [@cacheable/memoize](https://cacheable.org/docs/memoize/) provides a convenient way to implement the cache-aside pattern. It attempts to retrieve a value from cache, and if not found, calls the provided function to compute the value and store it in cache before returning it. Here are the options:
750
+ The `getOrSet` method that comes from [@cacheable/utils](https://cacheable.org/docs/utils/) provides a convenient way to implement the cache-aside pattern. It attempts to retrieve a value from cache, and if not found, calls the provided function to compute the value and store it in cache before returning it. Here are the options:
645
751
 
646
752
  ```typescript
647
753
  export type GetOrSetFunctionOptions = {
@@ -677,17 +783,17 @@ const function_ = async () => Math.random() * 100;
677
783
  const value = await cache.getOrSet(generateKey(), function_, { ttl: '1h' });
678
784
  ```
679
785
 
680
- To learn more go to [@cacheable/memoize](https://cacheable.org/docs/memoize/)
786
+ To learn more go to [@cacheable/utils](https://cacheable.org/docs/utils/)
681
787
 
682
788
  # v1 to v2 Changes
683
789
 
684
- `cacheable` is now using `@cacheable/utils`, `@cacheable/memoize`, and `@cacheable/memory` for its core functionality as we are moving to this modular architecture and plan to eventually have these modules across `cache-manager` and `flat-cache`. In addition there are some breaking changes:
790
+ `cacheable` is now using `@cacheable/utils` and `@cacheable/memory` for its core functionality as we are moving to this modular architecture and plan to eventually have these modules across `cache-manager` and `flat-cache`. In addition there are some breaking changes:
685
791
 
686
792
  * `get()` and `getMany()` no longer have the `raw` option but instead we have built out `getRaw()` and `getManyRaw()` to use.
687
793
  * All `get` related functions now support `nonBlocking` which means if `nonBlocking: true` the primary store will return what it has and then in the background will work to sync from secondary storage for any misses. You can disable this by setting at the `get` function level the option `nonBlocking: false` which will look for any missing keys in the secondary.
688
- * `Keyv` v5.5+ is now the recommended supported version as we are using its native `getMany*` and `getRaw*`
794
+ * `Keyv` v5.5+ is now the recommended supported version as we are using its native `getMany*`, `getRaw*`, and `hasMany` methods for improved performance
689
795
  * `Wrap` and `getOrSet` have been updated with more robust options including the ability to use your own `serialize` function for creating the key in `wrap`.
690
- * `hash` has now been updated with robust options and also an enum for setting the algorithm.
796
+ * `hash` has been split into async (`hash()` and `hashToNumber()`) and sync (`hashSync()` and `hashToNumberSync()`) methods. MD5 support has been removed. Now uses Hashery library with support for additional algorithms (SHA-384, FNV1, MURMER, CRC32).
691
797
 
692
798
  # How to Contribute
693
799
 
package/dist/index.cjs CHANGED
@@ -34,15 +34,14 @@ __export(index_exports, {
34
34
  calculateTtlFromExpiration: () => import_utils2.calculateTtlFromExpiration,
35
35
  createKeyv: () => import_memory2.createKeyv,
36
36
  getCascadingTtl: () => import_utils2.getCascadingTtl,
37
- getOrSet: () => import_memoize2.getOrSet,
37
+ getOrSet: () => import_utils2.getOrSet,
38
38
  hash: () => import_utils2.hash,
39
39
  shorthandToMilliseconds: () => import_utils2.shorthandToMilliseconds,
40
40
  shorthandToTime: () => import_utils2.shorthandToTime,
41
- wrap: () => import_memoize2.wrap,
42
- wrapSync: () => import_memoize2.wrapSync
41
+ wrap: () => import_utils2.wrap,
42
+ wrapSync: () => import_utils2.wrapSync
43
43
  });
44
44
  module.exports = __toCommonJS(index_exports);
45
- var import_memoize = require("@cacheable/memoize");
46
45
  var import_memory = require("@cacheable/memory");
47
46
  var import_utils = require("@cacheable/utils");
48
47
  var import_hookified2 = require("hookified");
@@ -149,7 +148,6 @@ var CacheableSync = class extends import_hookified.Hookified {
149
148
  };
150
149
 
151
150
  // src/index.ts
152
- var import_memoize2 = require("@cacheable/memoize");
153
151
  var import_memory2 = require("@cacheable/memory");
154
152
  var import_utils2 = require("@cacheable/utils");
155
153
  var import_keyv2 = require("keyv");
@@ -677,7 +675,7 @@ var Cacheable = class extends import_hookified2.Hookified {
677
675
  * @returns {Promise<boolean[]>} Whether the keys exist
678
676
  */
679
677
  async hasMany(keys) {
680
- const result = await this.hasManyKeyv(this._primary, keys);
678
+ const result = await this._primary.hasMany(keys);
681
679
  const missingKeys = [];
682
680
  for (const [i, key] of keys.entries()) {
683
681
  if (!result[i] && this._secondary) {
@@ -685,7 +683,7 @@ var Cacheable = class extends import_hookified2.Hookified {
685
683
  }
686
684
  }
687
685
  if (missingKeys.length > 0 && this._secondary) {
688
- const secondary = await this.hasManyKeyv(this._secondary, keys);
686
+ const secondary = await this._secondary.hasMany(keys);
689
687
  for (const [i, _key] of keys.entries()) {
690
688
  if (!result[i] && secondary[i]) {
691
689
  result[i] = secondary[i];
@@ -795,6 +793,7 @@ var Cacheable = class extends import_hookified2.Hookified {
795
793
  if (this._secondary) {
796
794
  promises.push(this._secondary.disconnect());
797
795
  }
796
+ promises.push(this._sync?.qified.disconnect());
798
797
  await (this._nonBlocking ? Promise.race(promises) : Promise.all(promises));
799
798
  }
800
799
  /**
@@ -809,18 +808,16 @@ var Cacheable = class extends import_hookified2.Hookified {
809
808
  wrap(function_, options) {
810
809
  const cacheAdapter = {
811
810
  get: async (key) => this.get(key),
811
+ /* v8 ignore next -- @preserve */
812
812
  has: async (key) => this.has(key),
813
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
814
813
  set: async (key, value, ttl) => {
815
814
  await this.set(key, value, ttl);
816
815
  },
817
- /* c8 ignore start */
818
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance interface
816
+ /* v8 ignore next -- @preserve */
819
817
  on: (event, listener) => {
820
818
  this.on(event, listener);
821
819
  },
822
- /* c8 ignore stop */
823
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
820
+ /* v8 ignore next -- @preserve */
824
821
  emit: (event, ...args) => this.emit(event, ...args)
825
822
  };
826
823
  const wrapOptions = {
@@ -832,7 +829,7 @@ var Cacheable = class extends import_hookified2.Hookified {
832
829
  cacheId: this._cacheId,
833
830
  serialize: options?.serialize
834
831
  };
835
- return (0, import_memoize.wrap)(function_, wrapOptions);
832
+ return (0, import_utils.wrap)(function_, wrapOptions);
836
833
  }
837
834
  /**
838
835
  * Retrieves the value associated with the given key from the cache. If the key is not found,
@@ -847,18 +844,15 @@ var Cacheable = class extends import_hookified2.Hookified {
847
844
  async getOrSet(key, function_, options) {
848
845
  const cacheAdapter = {
849
846
  get: async (key2) => this.get(key2),
847
+ /* v8 ignore next -- @preserve */
850
848
  has: async (key2) => this.has(key2),
851
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
852
849
  set: async (key2, value, ttl) => {
853
850
  await this.set(key2, value, ttl);
854
851
  },
855
- /* c8 ignore start */
856
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance interface
852
+ /* v8 ignore next -- @preserve */
857
853
  on: (event, listener) => {
858
854
  this.on(event, listener);
859
855
  },
860
- /* c8 ignore stop */
861
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
862
856
  emit: (event, ...args) => this.emit(event, ...args)
863
857
  };
864
858
  const getOrSetOptions = {
@@ -868,17 +862,29 @@ var Cacheable = class extends import_hookified2.Hookified {
868
862
  cacheErrors: options?.cacheErrors,
869
863
  throwErrors: options?.throwErrors
870
864
  };
871
- return (0, import_memoize.getOrSet)(key, function_, getOrSetOptions);
865
+ return (0, import_utils.getOrSet)(key, function_, getOrSetOptions);
872
866
  }
873
867
  /**
874
- * Will hash an object using the specified algorithm. The default algorithm is 'sha256'.
868
+ * Will hash an object asynchronously using the specified cryptographic algorithm.
869
+ * Use this for cryptographic algorithms (SHA-256, SHA-384, SHA-512).
870
+ * For non-cryptographic algorithms, use hashSync() for better performance.
875
871
  * @param {any} object the object to hash
876
- * @param {string} algorithm the hash algorithm to use. The default is 'sha256'
872
+ * @param {string} algorithm the hash algorithm to use. The default is 'SHA-256'
873
+ * @returns {Promise<string>} the hash of the object
874
+ */
875
+ async hash(object, algorithm = import_utils.HashAlgorithm.SHA256) {
876
+ return (0, import_utils.hash)(object, { algorithm });
877
+ }
878
+ /**
879
+ * Will hash an object synchronously using the specified non-cryptographic algorithm.
880
+ * Use this for non-cryptographic algorithms (DJB2, FNV1, MURMER, CRC32).
881
+ * For cryptographic algorithms, use hash() instead.
882
+ * @param {any} object the object to hash
883
+ * @param {string} algorithm the hash algorithm to use. The default is 'djb2'
877
884
  * @returns {string} the hash of the object
878
885
  */
879
- hash(object, algorithm = import_utils.HashAlgorithm.SHA256) {
880
- const validAlgorithm = Object.values(import_utils.HashAlgorithm).includes(algorithm) ? algorithm : import_utils.HashAlgorithm.SHA256;
881
- return (0, import_utils.hash)(object, { algorithm: validAlgorithm });
886
+ hashSync(object, algorithm = import_utils.HashAlgorithm.DJB2) {
887
+ return (0, import_utils.hashSync)(object, { algorithm });
882
888
  }
883
889
  async setManyKeyv(keyv, items) {
884
890
  const entries = [];
@@ -889,13 +895,6 @@ var Cacheable = class extends import_hookified2.Hookified {
889
895
  await keyv.setMany(entries);
890
896
  return true;
891
897
  }
892
- async hasManyKeyv(keyv, keys) {
893
- const promises = [];
894
- for (const key of keys) {
895
- promises.push(keyv.has(key));
896
- }
897
- return Promise.all(promises);
898
- }
899
898
  /**
900
899
  * Processes a single key from secondary store for getRaw operation
901
900
  * @param primary - the primary store to use
@@ -1085,3 +1084,4 @@ var Cacheable = class extends import_hookified2.Hookified {
1085
1084
  wrap,
1086
1085
  wrapSync
1087
1086
  });
1087
+ /* v8 ignore next -- @preserve */
package/dist/index.d.cts CHANGED
@@ -1,7 +1,5 @@
1
- import { WrapFunctionOptions, GetOrSetKey, GetOrSetFunctionOptions } from '@cacheable/memoize';
2
- export { GetOrSetFunctionOptions, GetOrSetKey, GetOrSetOptions, WrapOptions, WrapSyncOptions, getOrSet, wrap, wrapSync } from '@cacheable/memoize';
3
- import { Stats, CacheableItem, HashAlgorithm } from '@cacheable/utils';
4
- export { CacheableItem, Stats as CacheableStats, HashAlgorithm, calculateTtlFromExpiration, getCascadingTtl, hash, shorthandToMilliseconds, shorthandToTime } from '@cacheable/utils';
1
+ import { Stats, CacheableItem, WrapFunctionOptions, GetOrSetKey, GetOrSetFunctionOptions, HashAlgorithm } from '@cacheable/utils';
2
+ export { CacheableItem, Stats as CacheableStats, GetOrSetFunctionOptions, GetOrSetKey, GetOrSetOptions, HashAlgorithm, WrapOptions, WrapSyncOptions, calculateTtlFromExpiration, getCascadingTtl, getOrSet, hash, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync } from '@cacheable/utils';
5
3
  import { Hookified, HookifiedOptions } from 'hookified';
6
4
  import { Keyv, KeyvStoreAdapter, StoredDataRaw } from 'keyv';
7
5
  export { Keyv, KeyvHooks, KeyvOptions, KeyvStoreAdapter } from 'keyv';
@@ -408,14 +406,24 @@ declare class Cacheable extends Hookified {
408
406
  */
409
407
  getOrSet<T>(key: GetOrSetKey, function_: () => Promise<T>, options?: GetOrSetFunctionOptions): Promise<T | undefined>;
410
408
  /**
411
- * Will hash an object using the specified algorithm. The default algorithm is 'sha256'.
409
+ * Will hash an object asynchronously using the specified cryptographic algorithm.
410
+ * Use this for cryptographic algorithms (SHA-256, SHA-384, SHA-512).
411
+ * For non-cryptographic algorithms, use hashSync() for better performance.
412
412
  * @param {any} object the object to hash
413
- * @param {string} algorithm the hash algorithm to use. The default is 'sha256'
413
+ * @param {string} algorithm the hash algorithm to use. The default is 'SHA-256'
414
+ * @returns {Promise<string>} the hash of the object
415
+ */
416
+ hash(object: any, algorithm?: HashAlgorithm): Promise<string>;
417
+ /**
418
+ * Will hash an object synchronously using the specified non-cryptographic algorithm.
419
+ * Use this for non-cryptographic algorithms (DJB2, FNV1, MURMER, CRC32).
420
+ * For cryptographic algorithms, use hash() instead.
421
+ * @param {any} object the object to hash
422
+ * @param {string} algorithm the hash algorithm to use. The default is 'djb2'
414
423
  * @returns {string} the hash of the object
415
424
  */
416
- hash(object: any, algorithm?: HashAlgorithm): string;
425
+ hashSync(object: any, algorithm?: HashAlgorithm): string;
417
426
  private setManyKeyv;
418
- private hasManyKeyv;
419
427
  /**
420
428
  * Processes a single key from secondary store for getRaw operation
421
429
  * @param primary - the primary store to use
package/dist/index.d.ts CHANGED
@@ -1,7 +1,5 @@
1
- import { WrapFunctionOptions, GetOrSetKey, GetOrSetFunctionOptions } from '@cacheable/memoize';
2
- export { GetOrSetFunctionOptions, GetOrSetKey, GetOrSetOptions, WrapOptions, WrapSyncOptions, getOrSet, wrap, wrapSync } from '@cacheable/memoize';
3
- import { Stats, CacheableItem, HashAlgorithm } from '@cacheable/utils';
4
- export { CacheableItem, Stats as CacheableStats, HashAlgorithm, calculateTtlFromExpiration, getCascadingTtl, hash, shorthandToMilliseconds, shorthandToTime } from '@cacheable/utils';
1
+ import { Stats, CacheableItem, WrapFunctionOptions, GetOrSetKey, GetOrSetFunctionOptions, HashAlgorithm } from '@cacheable/utils';
2
+ export { CacheableItem, Stats as CacheableStats, GetOrSetFunctionOptions, GetOrSetKey, GetOrSetOptions, HashAlgorithm, WrapOptions, WrapSyncOptions, calculateTtlFromExpiration, getCascadingTtl, getOrSet, hash, shorthandToMilliseconds, shorthandToTime, wrap, wrapSync } from '@cacheable/utils';
5
3
  import { Hookified, HookifiedOptions } from 'hookified';
6
4
  import { Keyv, KeyvStoreAdapter, StoredDataRaw } from 'keyv';
7
5
  export { Keyv, KeyvHooks, KeyvOptions, KeyvStoreAdapter } from 'keyv';
@@ -408,14 +406,24 @@ declare class Cacheable extends Hookified {
408
406
  */
409
407
  getOrSet<T>(key: GetOrSetKey, function_: () => Promise<T>, options?: GetOrSetFunctionOptions): Promise<T | undefined>;
410
408
  /**
411
- * Will hash an object using the specified algorithm. The default algorithm is 'sha256'.
409
+ * Will hash an object asynchronously using the specified cryptographic algorithm.
410
+ * Use this for cryptographic algorithms (SHA-256, SHA-384, SHA-512).
411
+ * For non-cryptographic algorithms, use hashSync() for better performance.
412
412
  * @param {any} object the object to hash
413
- * @param {string} algorithm the hash algorithm to use. The default is 'sha256'
413
+ * @param {string} algorithm the hash algorithm to use. The default is 'SHA-256'
414
+ * @returns {Promise<string>} the hash of the object
415
+ */
416
+ hash(object: any, algorithm?: HashAlgorithm): Promise<string>;
417
+ /**
418
+ * Will hash an object synchronously using the specified non-cryptographic algorithm.
419
+ * Use this for non-cryptographic algorithms (DJB2, FNV1, MURMER, CRC32).
420
+ * For cryptographic algorithms, use hash() instead.
421
+ * @param {any} object the object to hash
422
+ * @param {string} algorithm the hash algorithm to use. The default is 'djb2'
414
423
  * @returns {string} the hash of the object
415
424
  */
416
- hash(object: any, algorithm?: HashAlgorithm): string;
425
+ hashSync(object: any, algorithm?: HashAlgorithm): string;
417
426
  private setManyKeyv;
418
- private hasManyKeyv;
419
427
  /**
420
428
  * Processes a single key from secondary store for getRaw operation
421
429
  * @param primary - the primary store to use
package/dist/index.js CHANGED
@@ -1,17 +1,16 @@
1
1
  // src/index.ts
2
- import {
3
- getOrSet,
4
- wrap
5
- } from "@cacheable/memoize";
6
2
  import { createKeyv } from "@cacheable/memory";
7
3
  import {
8
4
  Stats as CacheableStats,
9
5
  calculateTtlFromExpiration,
10
6
  getCascadingTtl,
7
+ getOrSet,
11
8
  HashAlgorithm,
12
9
  hash,
10
+ hashSync,
13
11
  isKeyvInstance,
14
- shorthandToMilliseconds
12
+ shorthandToMilliseconds,
13
+ wrap
15
14
  } from "@cacheable/utils";
16
15
  import { Hookified as Hookified2 } from "hookified";
17
16
  import {
@@ -119,11 +118,6 @@ var CacheableSync = class extends Hookified {
119
118
  };
120
119
 
121
120
  // src/index.ts
122
- import {
123
- getOrSet as getOrSet2,
124
- wrap as wrap2,
125
- wrapSync
126
- } from "@cacheable/memoize";
127
121
  import {
128
122
  CacheableMemory,
129
123
  createKeyv as createKeyv2,
@@ -132,11 +126,14 @@ import {
132
126
  import {
133
127
  calculateTtlFromExpiration as calculateTtlFromExpiration2,
134
128
  getCascadingTtl as getCascadingTtl2,
129
+ getOrSet as getOrSet2,
135
130
  HashAlgorithm as HashAlgorithm2,
136
131
  hash as hash2,
137
132
  Stats,
138
133
  shorthandToMilliseconds as shorthandToMilliseconds2,
139
- shorthandToTime
134
+ shorthandToTime,
135
+ wrap as wrap2,
136
+ wrapSync
140
137
  } from "@cacheable/utils";
141
138
  import { Keyv as Keyv2, KeyvHooks } from "keyv";
142
139
  var Cacheable = class extends Hookified2 {
@@ -663,7 +660,7 @@ var Cacheable = class extends Hookified2 {
663
660
  * @returns {Promise<boolean[]>} Whether the keys exist
664
661
  */
665
662
  async hasMany(keys) {
666
- const result = await this.hasManyKeyv(this._primary, keys);
663
+ const result = await this._primary.hasMany(keys);
667
664
  const missingKeys = [];
668
665
  for (const [i, key] of keys.entries()) {
669
666
  if (!result[i] && this._secondary) {
@@ -671,7 +668,7 @@ var Cacheable = class extends Hookified2 {
671
668
  }
672
669
  }
673
670
  if (missingKeys.length > 0 && this._secondary) {
674
- const secondary = await this.hasManyKeyv(this._secondary, keys);
671
+ const secondary = await this._secondary.hasMany(keys);
675
672
  for (const [i, _key] of keys.entries()) {
676
673
  if (!result[i] && secondary[i]) {
677
674
  result[i] = secondary[i];
@@ -781,6 +778,7 @@ var Cacheable = class extends Hookified2 {
781
778
  if (this._secondary) {
782
779
  promises.push(this._secondary.disconnect());
783
780
  }
781
+ promises.push(this._sync?.qified.disconnect());
784
782
  await (this._nonBlocking ? Promise.race(promises) : Promise.all(promises));
785
783
  }
786
784
  /**
@@ -795,18 +793,16 @@ var Cacheable = class extends Hookified2 {
795
793
  wrap(function_, options) {
796
794
  const cacheAdapter = {
797
795
  get: async (key) => this.get(key),
796
+ /* v8 ignore next -- @preserve */
798
797
  has: async (key) => this.has(key),
799
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
800
798
  set: async (key, value, ttl) => {
801
799
  await this.set(key, value, ttl);
802
800
  },
803
- /* c8 ignore start */
804
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance interface
801
+ /* v8 ignore next -- @preserve */
805
802
  on: (event, listener) => {
806
803
  this.on(event, listener);
807
804
  },
808
- /* c8 ignore stop */
809
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
805
+ /* v8 ignore next -- @preserve */
810
806
  emit: (event, ...args) => this.emit(event, ...args)
811
807
  };
812
808
  const wrapOptions = {
@@ -833,18 +829,15 @@ var Cacheable = class extends Hookified2 {
833
829
  async getOrSet(key, function_, options) {
834
830
  const cacheAdapter = {
835
831
  get: async (key2) => this.get(key2),
832
+ /* v8 ignore next -- @preserve */
836
833
  has: async (key2) => this.has(key2),
837
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
838
834
  set: async (key2, value, ttl) => {
839
835
  await this.set(key2, value, ttl);
840
836
  },
841
- /* c8 ignore start */
842
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance interface
837
+ /* v8 ignore next -- @preserve */
843
838
  on: (event, listener) => {
844
839
  this.on(event, listener);
845
840
  },
846
- /* c8 ignore stop */
847
- // biome-ignore lint/suspicious/noExplicitAny: CacheInstance requires any type
848
841
  emit: (event, ...args) => this.emit(event, ...args)
849
842
  };
850
843
  const getOrSetOptions = {
@@ -857,14 +850,26 @@ var Cacheable = class extends Hookified2 {
857
850
  return getOrSet(key, function_, getOrSetOptions);
858
851
  }
859
852
  /**
860
- * Will hash an object using the specified algorithm. The default algorithm is 'sha256'.
853
+ * Will hash an object asynchronously using the specified cryptographic algorithm.
854
+ * Use this for cryptographic algorithms (SHA-256, SHA-384, SHA-512).
855
+ * For non-cryptographic algorithms, use hashSync() for better performance.
856
+ * @param {any} object the object to hash
857
+ * @param {string} algorithm the hash algorithm to use. The default is 'SHA-256'
858
+ * @returns {Promise<string>} the hash of the object
859
+ */
860
+ async hash(object, algorithm = HashAlgorithm.SHA256) {
861
+ return hash(object, { algorithm });
862
+ }
863
+ /**
864
+ * Will hash an object synchronously using the specified non-cryptographic algorithm.
865
+ * Use this for non-cryptographic algorithms (DJB2, FNV1, MURMER, CRC32).
866
+ * For cryptographic algorithms, use hash() instead.
861
867
  * @param {any} object the object to hash
862
- * @param {string} algorithm the hash algorithm to use. The default is 'sha256'
868
+ * @param {string} algorithm the hash algorithm to use. The default is 'djb2'
863
869
  * @returns {string} the hash of the object
864
870
  */
865
- hash(object, algorithm = HashAlgorithm.SHA256) {
866
- const validAlgorithm = Object.values(HashAlgorithm).includes(algorithm) ? algorithm : HashAlgorithm.SHA256;
867
- return hash(object, { algorithm: validAlgorithm });
871
+ hashSync(object, algorithm = HashAlgorithm.DJB2) {
872
+ return hashSync(object, { algorithm });
868
873
  }
869
874
  async setManyKeyv(keyv, items) {
870
875
  const entries = [];
@@ -875,13 +880,6 @@ var Cacheable = class extends Hookified2 {
875
880
  await keyv.setMany(entries);
876
881
  return true;
877
882
  }
878
- async hasManyKeyv(keyv, keys) {
879
- const promises = [];
880
- for (const key of keys) {
881
- promises.push(keyv.has(key));
882
- }
883
- return Promise.all(promises);
884
- }
885
883
  /**
886
884
  * Processes a single key from secondary store for getRaw operation
887
885
  * @param primary - the primary store to use
@@ -1070,3 +1068,4 @@ export {
1070
1068
  wrap2 as wrap,
1071
1069
  wrapSync
1072
1070
  };
1071
+ /* v8 ignore next -- @preserve */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cacheable",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "High Performance Layer 1 / Layer 2 Caching with Keyv Storage",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -21,26 +21,25 @@
21
21
  "license": "MIT",
22
22
  "private": false,
23
23
  "devDependencies": {
24
- "@biomejs/biome": "^2.2.6",
24
+ "@biomejs/biome": "^2.3.5",
25
25
  "@faker-js/faker": "^10.1.0",
26
- "@keyv/redis": "^5.1.3",
27
- "@keyv/valkey": "^1.0.10",
28
- "@qified/redis": "^0.5.0",
29
- "@types/node": "^24.8.1",
30
- "@vitest/coverage-v8": "^3.2.4",
26
+ "@keyv/redis": "^5.1.4",
27
+ "@keyv/valkey": "^1.0.11",
28
+ "@qified/redis": "^0.5.2",
29
+ "@types/node": "^24.10.1",
30
+ "@vitest/coverage-v8": "^4.0.9",
31
31
  "lru-cache": "^11.2.2",
32
- "rimraf": "^6.0.1",
33
- "tsup": "^8.5.0",
32
+ "rimraf": "^6.1.0",
33
+ "tsup": "^8.5.1",
34
34
  "typescript": "^5.9.3",
35
- "vitest": "^3.2.4"
35
+ "vitest": "^4.0.9"
36
36
  },
37
37
  "dependencies": {
38
- "hookified": "^1.12.2",
39
- "keyv": "^5.5.3",
40
- "qified": "^0.5.0",
41
- "@cacheable/memoize": "^2.0.3",
42
- "@cacheable/memory": "^2.0.3",
43
- "@cacheable/utils": "^2.1.0"
38
+ "hookified": "^1.13.0",
39
+ "keyv": "^5.5.4",
40
+ "qified": "^0.5.2",
41
+ "@cacheable/memory": "^2.0.5",
42
+ "@cacheable/utils": "^2.3.0"
44
43
  },
45
44
  "keywords": [
46
45
  "cacheable",