Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cacheable

Package Overview
Dependencies
Maintainers
0
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cacheable - npm Package Compare versions

Comparing version 1.8.1 to 1.8.2

99

dist/index.d.ts

@@ -112,2 +112,20 @@ import { KeyvStoreAdapter, StoredData, Keyv } from 'keyv';

type WrapOptions = {
ttl?: number | string;
keyPrefix?: string;
cache: Cacheable;
};
type WrapSyncOptions = {
ttl?: number | string;
keyPrefix?: string;
cache: CacheableMemory;
};
type WrapFunctionOptions = {
ttl?: number | string;
keyPrefix: string;
};
type AnyFunction = (...arguments_: any[]) => any;
declare function wrapSync<T>(function_: AnyFunction, options: WrapSyncOptions): AnyFunction;
declare function wrap<T>(function_: AnyFunction, options: WrapOptions): AnyFunction;
/**

@@ -129,2 +147,3 @@ * @typedef {Object} CacheableMemoryOptions

declare class CacheableMemory {
private _lru;
private readonly _hashCache;

@@ -141,3 +160,2 @@ private readonly _hash0;

private readonly _hash9;
private readonly _lru;
private _ttl;

@@ -289,14 +307,20 @@ private _useClone;

/**
* Hash the key. this is used to determine which store to use (internal use)
* @param {string} key - The key to hash
* @returns {number} - The hash number
*/
hashKey(key: string): number;
/**
* Get the store based on the key (internal use)
* @param {string} key - The key to get the store
* @returns {Map<string, any>} - The store
* @returns {CacheableHashStore} - The store
*/
getStore(key: string): Map<string, any>;
getStore(key: string): Map<string, CacheableStoreItem>;
/**
* Get the store based on the hash (internal use)
* @param {number} hash
* @returns {Map<string, CacheableStoreItem>}
*/
getStoreFromHash(hash: number): Map<string, CacheableStoreItem>;
/**
* Hash the key (internal use)
* @param key
* @returns {number} from 0 to 9
*/
hashKey(key: string): number;
/**
* Clone the value. This is for internal use

@@ -352,6 +376,3 @@ * @param {any} value - The value to clone

*/
wrap<T>(function_: (...arguments_: any[]) => T, options?: {
ttl?: number;
key?: string;
}): (...arguments_: any[]) => T;
wrap<T>(function_: (...arguments_: any[]) => T, options: WrapFunctionOptions): (...arguments_: any[]) => T;
private isPrimitive;

@@ -362,7 +383,14 @@ private concatStores;

type KeyvCacheableMemoryOptions = CacheableMemoryOptions & {
namespace?: string;
};
declare class KeyvCacheableMemory implements KeyvStoreAdapter {
opts: CacheableMemoryOptions;
namespace?: string | undefined;
private readonly _cache;
constructor(options?: CacheableMemoryOptions);
private readonly _defaultCache;
private readonly _nCache;
private _namespace?;
constructor(options?: KeyvCacheableMemoryOptions);
get namespace(): string | undefined;
set namespace(value: string | undefined);
get store(): CacheableMemory;
get<Value>(key: string): Promise<StoredData<Value> | undefined>;

@@ -381,2 +409,3 @@ getMany<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;

on(event: string, listener: (...arguments_: any[]) => void): this;
getStore(namespace?: string): CacheableMemory;
}

@@ -387,16 +416,2 @@

type WrapOptions = {
ttl?: number | string;
key?: string;
cache: Cacheable;
};
type WrapSyncOptions = {
ttl?: number | string;
key?: string;
cache: CacheableMemory;
};
type AnyFunction = (...arguments_: any[]) => any;
declare function wrapSync<T>(function_: AnyFunction, options: WrapSyncOptions): AnyFunction;
declare function wrap<T>(function_: AnyFunction, options: WrapOptions): AnyFunction;
declare enum CacheableHooks {

@@ -421,2 +436,3 @@ BEFORE_SET = "BEFORE_SET",

ttl?: number | string;
namespace?: string | (() => string);
};

@@ -429,2 +445,3 @@ declare class Cacheable extends Hookified {

private readonly _stats;
private _namespace?;
/**

@@ -436,2 +453,13 @@ * Creates a new cacheable instance

/**
* The namespace for the cacheable instance
* @returns {string | (() => string) | undefined} The namespace for the cacheable instance
*/
get namespace(): string | (() => string) | undefined;
/**
* Sets the namespace for the cacheable instance
* @param {string | (() => string) | undefined} namespace The namespace for the cacheable instance
* @returns {void}
*/
set namespace(namespace: string | (() => string) | undefined);
/**
* The statistics for the cacheable instance

@@ -529,2 +557,3 @@ * @returns {CacheableStats} The statistics for the cacheable instance

setSecondary(secondary: Keyv | KeyvStoreAdapter): void;
getNameSpace(): string | undefined;
/**

@@ -546,5 +575,4 @@ * Gets the value of the key. If the key does not exist in the primary store then it will check the secondary store.

* @param {T} value The value to set
* @param {number | string} [ttl] Time to Live - If you set a number it is miliseconds, if you set a string it is a human-readable
* format such as `1s` for 1 second or `1h` for 1 hour. Setting undefined means that it will use the default time-to-live. If both are
* undefined then it will not have a time-to-live.
* @param {number | string} [ttl] set a number it is miliseconds, set a string it is a human-readable
* format such as `1s` for 1 second or `1h` for 1 hour. Setting undefined means that it will use the default time-to-live.
* @returns {boolean} Whether the value was set

@@ -613,6 +641,3 @@ */

*/
wrap<T>(function_: (...arguments_: any[]) => T, options?: {
ttl?: number;
key?: string;
}): (...arguments_: any[]) => T;
wrap<T>(function_: (...arguments_: any[]) => T, options: WrapFunctionOptions): (...arguments_: any[]) => T;
/**

@@ -619,0 +644,0 @@ * Will hash an object using the specified algorithm. The default algorithm is 'sha256'.

@@ -72,7 +72,19 @@ // src/index.ts

// src/hash.ts
import * as crypto from "node:crypto";
function hash(object, algorithm = "sha256") {
const objectString = JSON.stringify(object);
if (!crypto.getHashes().includes(algorithm)) {
throw new Error(`Unsupported hash algorithm: '${algorithm}'`);
}
const hasher = crypto.createHash(algorithm);
hasher.update(objectString);
return hasher.digest("hex");
}
// src/wrap.ts
function wrapSync(function_, options) {
const { ttl, key, cache } = options;
const { ttl, keyPrefix, cache } = options;
return function(...arguments_) {
const cacheKey = key ?? cache.hash(arguments_);
const cacheKey = createWrapKey(function_, arguments_, keyPrefix);
let value = cache.get(cacheKey);

@@ -87,5 +99,5 @@ if (value === void 0) {

function wrap(function_, options) {
const { ttl, key, cache } = options;
const { ttl, keyPrefix, cache } = options;
return async function(...arguments_) {
const cacheKey = key ?? cache.hash(arguments_);
const cacheKey = createWrapKey(function_, arguments_, keyPrefix);
let value = await cache.get(cacheKey);

@@ -99,2 +111,8 @@ if (value === void 0) {

}
function createWrapKey(function_, arguments_, keyPrefix) {
if (!keyPrefix) {
return `${function_.name}::${hash(arguments_)}`;
}
return `${keyPrefix}::${function_.name}::${hash(arguments_)}`;
}

@@ -174,16 +192,5 @@ // src/memory-lru.ts

// src/hash.ts
import * as crypto from "node:crypto";
function hash(object, algorithm = "sha256") {
const objectString = JSON.stringify(object);
if (!crypto.getHashes().includes(algorithm)) {
throw new Error(`Unsupported hash algorithm: '${algorithm}'`);
}
const hasher = crypto.createHash(algorithm);
hasher.update(objectString);
return hasher.digest("hex");
}
// src/memory.ts
var CacheableMemory = class {
_lru = new DoublyLinkedList();
_hashCache = /* @__PURE__ */ new Map();

@@ -200,3 +207,2 @@ _hash0 = /* @__PURE__ */ new Map();

_hash9 = /* @__PURE__ */ new Map();
_lru = new DoublyLinkedList();
_ttl;

@@ -403,8 +409,7 @@ // Turned off by default

}
store.set(key, {
const item = { key, value, expires };
store.set(
key,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
value,
expires
});
item
);
}

@@ -503,30 +508,20 @@ /**

this._hashCache.clear();
this._lru = new DoublyLinkedList();
}
/**
* Hash the key. this is used to determine which store to use (internal use)
* @param {string} key - The key to hash
* @returns {number} - The hash number
* Get the store based on the key (internal use)
* @param {string} key - The key to get the store
* @returns {CacheableHashStore} - The store
*/
hashKey(key) {
const cacheHashNumber = this._hashCache.get(key);
if (cacheHashNumber) {
return cacheHashNumber;
}
let hash2 = 0;
const primeMultiplier = 31;
for (let i = 0; i < key.length; i++) {
hash2 = hash2 * primeMultiplier + key.charCodeAt(i);
}
const result = Math.abs(hash2) % 10;
this._hashCache.set(key, result);
return result;
getStore(key) {
const hash2 = this.hashKey(key);
return this.getStoreFromHash(hash2);
}
/**
* Get the store based on the key (internal use)
* @param {string} key - The key to get the store
* @returns {Map<string, any>} - The store
* Get the store based on the hash (internal use)
* @param {number} hash
* @returns {Map<string, CacheableStoreItem>}
*/
getStore(key) {
const hashKey = this.hashKey(key);
switch (hashKey) {
getStoreFromHash(hash2) {
switch (hash2) {
case 1: {

@@ -565,2 +560,21 @@ return this._hash1;

/**
* Hash the key (internal use)
* @param key
* @returns {number} from 0 to 9
*/
hashKey(key) {
const cacheHashNumber = this._hashCache.get(key);
if (cacheHashNumber) {
return cacheHashNumber;
}
let hash2 = 0;
const primeMultiplier = 31;
for (let i = 0; i < key.length; i++) {
hash2 = hash2 * primeMultiplier + key.charCodeAt(i);
}
const result = Math.abs(hash2) % 10;
this._hashCache.set(key, result);
return result;
}
/**
* Clone the value. This is for internal use

@@ -663,6 +677,6 @@ * @param {any} value - The value to clone

*/
wrap(function_, options = {}) {
wrap(function_, options) {
const wrapOptions = {
ttl: options.ttl,
key: options.key,
keyPrefix: options.keyPrefix,
cache: this

@@ -683,4 +697,3 @@ };

concatStores() {
const result = new Map([...this._hash0, ...this._hash1, ...this._hash2, ...this._hash3, ...this._hash4, ...this._hash5, ...this._hash6, ...this._hash7, ...this._hash8, ...this._hash9]);
return result;
return new Map([...this._hash0, ...this._hash1, ...this._hash2, ...this._hash3, ...this._hash4, ...this._hash5, ...this._hash6, ...this._hash7, ...this._hash8, ...this._hash9]);
}

@@ -706,12 +719,26 @@ setTtl(ttl) {

};
namespace;
_cache = new CacheableMemory();
_defaultCache = new CacheableMemory();
_nCache = /* @__PURE__ */ new Map();
_namespace;
constructor(options) {
if (options) {
this.opts = options;
this._cache = new CacheableMemory(options);
this._defaultCache = new CacheableMemory(options);
if (options.namespace) {
this._namespace = options.namespace;
this._nCache.set(this._namespace, new CacheableMemory(options));
}
}
}
get namespace() {
return this._namespace;
}
set namespace(value) {
this._namespace = value;
}
get store() {
return this.getStore(this._namespace);
}
async get(key) {
const result = this._cache.get(key);
const result = this.getStore(this._namespace).get(key);
if (result) {

@@ -723,24 +750,24 @@ return result;

async getMany(keys) {
const result = this._cache.getMany(keys);
const result = this.getStore(this._namespace).getMany(keys);
return result;
}
async set(key, value, ttl) {
this._cache.set(key, value, ttl);
this.getStore(this._namespace).set(key, value, ttl);
}
async setMany(values) {
this._cache.setMany(values);
this.getStore(this._namespace).setMany(values);
}
async delete(key) {
this._cache.delete(key);
this.getStore(this._namespace).delete(key);
return true;
}
async deleteMany(key) {
this._cache.deleteMany(key);
this.getStore(this._namespace).deleteMany(key);
return true;
}
async clear() {
this._cache.clear();
this.getStore(this._namespace).clear();
}
async has(key) {
return this._cache.has(key);
return this.getStore(this._namespace).has(key);
}

@@ -750,2 +777,11 @@ on(event, listener) {

}
getStore(namespace) {
if (!namespace) {
return this._defaultCache;
}
if (!this._nCache.has(namespace)) {
this._nCache.set(namespace, new CacheableMemory(this.opts));
}
return this._nCache.get(namespace);
}
};

@@ -996,2 +1032,3 @@

_stats = new CacheableStats({ enabled: false });
_namespace;
/**

@@ -1018,4 +1055,30 @@ * Creates a new cacheable instance

}
if (options?.namespace) {
this._namespace = options.namespace;
this._primary.namespace = this.getNameSpace();
if (this._secondary) {
this._secondary.namespace = this.getNameSpace();
}
}
}
/**
* The namespace for the cacheable instance
* @returns {string | (() => string) | undefined} The namespace for the cacheable instance
*/
get namespace() {
return this._namespace;
}
/**
* Sets the namespace for the cacheable instance
* @param {string | (() => string) | undefined} namespace The namespace for the cacheable instance
* @returns {void}
*/
set namespace(namespace) {
this._namespace = namespace;
this._primary.namespace = this.getNameSpace();
if (this._secondary) {
this._secondary.namespace = this.getNameSpace();
}
}
/**
* The statistics for the cacheable instance

@@ -1135,2 +1198,8 @@ * @returns {CacheableStats} The statistics for the cacheable instance

}
getNameSpace() {
if (typeof this._namespace === "function") {
return this._namespace();
}
return this._namespace;
}
/**

@@ -1213,5 +1282,4 @@ * Gets the value of the key. If the key does not exist in the primary store then it will check the secondary store.

* @param {T} value The value to set
* @param {number | string} [ttl] Time to Live - If you set a number it is miliseconds, if you set a string it is a human-readable
* format such as `1s` for 1 second or `1h` for 1 hour. Setting undefined means that it will use the default time-to-live. If both are
* undefined then it will not have a time-to-live.
* @param {number | string} [ttl] set a number it is miliseconds, set a string it is a human-readable
* format such as `1s` for 1 second or `1h` for 1 hour. Setting undefined means that it will use the default time-to-live.
* @returns {boolean} Whether the value was set

@@ -1430,6 +1498,6 @@ */

*/
wrap(function_, options = {}) {
wrap(function_, options) {
const wrapOptions = {
ttl: options.ttl,
key: options.key,
keyPrefix: options.keyPrefix,
cache: this

@@ -1436,0 +1504,0 @@ };

{
"name": "cacheable",
"version": "1.8.1",
"version": "1.8.2",
"description": "Simple Caching Engine using Keyv",

@@ -25,14 +25,14 @@ "type": "module",

"@keyv/redis": "^3.0.1",
"@types/node": "^22.7.4",
"@vitest/coverage-v8": "^2.1.1",
"@types/node": "^22.8.1",
"@vitest/coverage-v8": "^2.1.3",
"lru-cache": "^11.0.1",
"rimraf": "^6.0.1",
"tsup": "^8.3.0",
"typescript": "^5.6.2",
"vitest": "^2.1.1",
"tsup": "^8.3.5",
"typescript": "^5.6.3",
"vitest": "^2.1.3",
"xo": "^0.59.3"
},
"dependencies": {
"hookified": "^1.1.0",
"keyv": "^5.0.3"
"hookified": "^1.4.0",
"keyv": "^5.1.2"
},

@@ -39,0 +39,0 @@ "keywords": [

@@ -195,2 +195,3 @@ [<img align="center" src="https://cacheable.org/logo.svg" alt="Cacheable" />](https://github.com/jaredwray/cacheable)

* `ttl`: The default time to live for the cache in milliseconds. Default is `undefined` which is disabled.
* `namespace`: The namespace for the cache. Default is `undefined`.

@@ -237,2 +238,3 @@ # Cacheable Statistics (Instance Only)

* `secondary`: The secondary store for the cache (layer 2) usually a persistent cache by Keyv.
* `namespace`: The namespace for the cache. Default is `undefined`. This will set the namespace for the primary and secondary stores.
* `nonBlocking`: If the secondary store is non-blocking. Default is `false`.

@@ -301,7 +303,11 @@ * `stats`: The statistics for this instance which includes `hits`, `misses`, `sets`, `deletes`, `clears`, `errors`, `count`, `vsize`, `ksize`.

const asyncFunction = async (value: number) => {
return value * 2;
return Math.random() * value;
};
const cache = new Cacheable();
const wrappedFunction = cache.wrap(asyncFunction, { ttl: '1h' });
const options = {
ttl: '1h', // 1 hour
keyPrefix: 'p1', // key prefix. This is used if you have multiple functions and need to set a unique prefix.
}
const wrappedFunction = cache.wrap(asyncFunction, options);
console.log(await wrappedFunction(2)); // 4

@@ -308,0 +314,0 @@ console.log(await wrappedFunction(2)); // 4 from cache

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc