cachimbo 0.0.5 → 0.0.6

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["options","wrappedData: Record<string, WeakValue>","data: Record<string, T | null>","data: Record<string, T | null>","raw: [string, string][]","data: Record<string, T | null>","data: Record<string, T | null>","result: Record<string, T | null>","promise","items: [string, Promise<T | null>][]","remainingKeys: string[]","item: CachedItem<T>","items: Record<string, T | null>","items: Record<string, CachedItem<T>>","didTriggerLoad: boolean","loadFinishAt: number"],"sources":["../src/base/index.ts","../src/base/local.ts","../src/local/lru/index.ts","../src/local/ttl/index.ts","../src/local/map/index.ts","../src/local/weak/index.ts","../src/local/cloning/index.ts","../src/local/noop/index.ts","../src/remote/ioredis/index.ts","../src/remote/redis/index.ts","../src/remote/valkey-glide/index.ts","../src/remote/memcache/index.ts","../src/remote/memjs/index.ts","../src/remote/workers-kv/index.ts","../src/remote/keyv/index.ts","../src/layers/async-lazy/index.ts","../src/layers/coalescing/index.ts","../src/layers/jittering/index.ts","../src/layers/key-transforming/index.ts","../src/layers/swr/index.ts","../src/layers/tiered/index.ts","../src/layers/metrics/index.ts"],"sourcesContent":["import type { BaseCacheOptions, ICache, SetCacheOptions } from '../types/cache.js';\r\nimport type { Logger } from '../types/logger.js';\r\n\r\n/**\r\n * The base implementation of a cache.\r\n *\r\n * This class only requires subclasses to implement {@link ICache#get}, {@link ICache#set} and {@link ICache#delete}.\r\n * All other methods fall back into these three.\r\n */\r\nexport abstract class BaseCache implements ICache {\r\n protected readonly name?: string;\r\n protected readonly logger?: Logger;\r\n\r\n protected constructor(options: BaseCacheOptions) {\r\n this.name = options.name;\r\n this.logger = options.logger;\r\n }\r\n\r\n abstract get<T>(key: string): Promise<T | null>;\r\n\r\n abstract set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;\r\n\r\n abstract delete(key: string): Promise<void>;\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n let data = await this.get<T>(key);\r\n\r\n if (data !== null) {\r\n this.logger?.debug(this.name, '[getOrLoad] Returning from cache.', 'key =', key);\r\n\r\n return data;\r\n }\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Refreshing the cache...', 'key =', key);\r\n\r\n data = await load();\r\n\r\n await this.set(key, data, options);\r\n\r\n return data;\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Reading all keys in parallel...', 'keys =', keys);\r\n\r\n return Object.fromEntries(\r\n await Promise.all(\r\n keys.map(async key => [key, await this.get<any>(key)]),\r\n ),\r\n );\r\n }\r\n\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany] Writing all keys in parallel...', 'data =', data);\r\n\r\n await Promise.all(\r\n Object.entries(data).map(([key, value]) =>\r\n this.set(key, value, options)\r\n ),\r\n );\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany] Deleting all keys in parallel...', 'keys =', keys);\r\n\r\n await Promise.all(\r\n keys.map(key => this.delete(key)),\r\n );\r\n }\r\n\r\n}\r\n","import type { SetCacheOptions } from '../types/cache.js';\r\nimport { BaseCache } from './index.js';\r\n\r\ntype LocalCacheDisposeListener<T = any> = (key: string, value: T, reason?: string) => void;\r\n\r\n/**\r\n * Internal methods for synchronous cache operations.\r\n * @experimental\r\n */\r\nexport interface LocalCacheInternal {\r\n _get<T>(key: string): T | null;\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void;\r\n _delete(key: string): void;\r\n _getMany<T>(keys: string[]): Record<string, T | null>;\r\n _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void;\r\n _deleteMany(keys: string[]): void;\r\n _addDisposeListener(listener: LocalCacheDisposeListener): void;\r\n}\r\n\r\nexport abstract class BaseLocalCache extends BaseCache {\r\n protected disposeListeners: LocalCacheDisposeListener[] = [];\r\n\r\n /**\r\n * Reads the cached resource from a key (synchronous version)\r\n */\r\n protected abstract _get<T>(key: string): T | null;\r\n\r\n /**\r\n * Writes a resource into cache (synchronous version)\r\n */\r\n protected abstract _set<T>(key: string, value: T, options?: SetCacheOptions): void;\r\n\r\n /**\r\n * Deletes a cached resource by a key. (synchronous version)\r\n */\r\n protected abstract _delete(key: string): void;\r\n\r\n /**\r\n * Reads cached resources by their keys. (synchronous version)\r\n */\r\n protected _getMany<T>(keys: string[]): Record<string, T | null> {\r\n return Object.fromEntries(\r\n keys.map(key => [key, this._get<T>(key)])\r\n );\r\n }\r\n\r\n /**\r\n * Writes resources into cache. (synchronous version)\r\n */\r\n protected _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void {\r\n for (const [key, value] of Object.entries(data)) {\r\n this._set<T>(key, value, options);\r\n }\r\n }\r\n\r\n /**\r\n * Deletes many cached resources by their keys. (synchronous version)\r\n */\r\n protected _deleteMany(keys: string[]): void {\r\n for (const key of keys) {\r\n this._delete(key);\r\n }\r\n }\r\n\r\n /**\r\n * Adds a listener that will be called when a cached item is disposed.\r\n *\r\n * @param listener The listener function to add.\r\n */\r\n protected _addDisposeListener(listener: LocalCacheDisposeListener): void {\r\n this.disposeListeners.push(listener);\r\n }\r\n\r\n /**\r\n * Gets access to the internal synchronous methods.\r\n * @experimental\r\n */\r\n get internal(): LocalCacheInternal {\r\n return this as unknown as LocalCacheInternal;\r\n }\r\n\r\n /** @sealed **/\r\n get<T>(key: string): Promise<T | null> {\r\n return Promise.resolve(this._get<T>(key));\r\n }\r\n\r\n /** @sealed **/\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this._set(key, value, options);\r\n return Promise.resolve();\r\n }\r\n\r\n /** @sealed **/\r\n delete(key: string): Promise<void> {\r\n this._delete(key);\r\n return Promise.resolve();\r\n }\r\n\r\n /** @sealed **/\r\n override getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return Promise.resolve(this._getMany(keys));\r\n }\r\n\r\n /** @sealed **/\r\n override setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this._setMany(data, options);\r\n return Promise.resolve();\r\n }\r\n\r\n /** @sealed **/\r\n override deleteMany(keys: string[]): Promise<void> {\r\n this._deleteMany(keys);\r\n return Promise.resolve();\r\n }\r\n\r\n protected onDispose(key: string, value: any, reason?: string): void {\r\n for (const listener of this.disposeListeners) {\r\n listener(key, value, reason);\r\n }\r\n }\r\n\r\n}\r\n","import { LRUCache } from 'lru-cache';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache } from '../../base/local.js';\r\n\r\nexport interface ExistingLRUCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The existing instance of a LRUCache.\r\n */\r\n cache: LRUCache<string, any, () => Promise<any>>;\r\n\r\n /**\r\n * Whether it should call {@link LRUCache#fetch} when `getOrLoad` is called.\r\n *\r\n * For that, {@link LRUCache#fetchMethod} needs to call the context function:\r\n * ```ts\r\n * new LRUCache<string, any, () => Promise<any>>({\r\n * fetchMethod: (_key, _staleValue, options) => options.context(),\r\n * });\r\n * ```\r\n */\r\n shouldUseFetch?: boolean;\r\n}\r\n\r\nexport interface LocalLRUCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The default Time to Live (in seconds)\r\n */\r\n ttl?: number;\r\n\r\n /**\r\n * The maximum amount of items stored\r\n */\r\n max?: number;\r\n}\r\n\r\n/**\r\n * An in-memory cache implementation of a Least-Recently-Used cache eviction algorithm.\r\n *\r\n * It allows setting an expiration time and a limit of cached items.\r\n *\r\n * Once the limit of items is reached, the least recently used items will be purged.\r\n */\r\nexport class LocalLRUCache extends BaseLocalCache {\r\n protected readonly cache: LRUCache<string, any, () => Promise<any>>;\r\n protected shouldUseFetch?: boolean;\r\n\r\n constructor(options: LocalLRUCacheOptions | ExistingLRUCacheOptions = {}) {\r\n super(options);\r\n\r\n if ('cache' in options) {\r\n this.cache = options.cache;\r\n this.shouldUseFetch = options.shouldUseFetch;\r\n } else {\r\n this.cache = new LRUCache<string, any, () => Promise<any>>({\r\n ttl: options.ttl ? options.ttl * 1000 : undefined,\r\n max: options.max || 10_000,\r\n ttlAutopurge: false,\r\n fetchMethod: (_key, _staleValue, options) => options.context(),\r\n disposeAfter: (value, key, reason) => this.onDispose(key, value, reason),\r\n });\r\n this.shouldUseFetch = true;\r\n }\r\n }\r\n\r\n /** @internal */\r\n _get<T>(key: string): T | null {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const data = this.cache.get(key);\r\n\r\n return data === undefined ? null : data;\r\n }\r\n\r\n /** @internal */\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const ttl = options?.ttl;\r\n\r\n this.cache.set(key, value, {\r\n ttl: ttl ? ttl * 1000 : undefined,\r\n });\r\n }\r\n\r\n /** @internal */\r\n _delete(key: string): void {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n this.cache.delete(key);\r\n }\r\n\r\n override getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n if (!this.shouldUseFetch) {\r\n return super.getOrLoad(key, load, options);\r\n }\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Running LRUCache\\'s fetch...', 'key =', key);\r\n\r\n const ttl = options?.ttl;\r\n\r\n return this.cache.fetch(key, {\r\n context: load,\r\n ttl: ttl ? ttl * 1000 : undefined,\r\n });\r\n }\r\n\r\n}\r\n","import { TTLCache } from '@isaacs/ttlcache';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache } from '../../base/local.js';\r\n\r\nexport interface ExistingTTLCacheOptions extends BaseCacheOptions {\r\n /**\r\n * Existing instance of a TTLCache\r\n */\r\n cache: TTLCache<string, any>;\r\n}\r\n\r\nexport interface LocalTTLCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The default Time to Live (in seconds)\r\n */\r\n ttl?: number;\r\n\r\n /**\r\n * The maximum amount of items stored\r\n */\r\n max?: number;\r\n}\r\n\r\n/**\r\n * An in-memory cache implementation that allows setting an expiration time and a limit of cached items.\r\n *\r\n * Once the limit of items is reached, the soonest expiring items will be purged.\r\n */\r\nexport class LocalTTLCache extends BaseLocalCache {\r\n protected readonly cache: TTLCache<string, any>;\r\n\r\n constructor(options: LocalTTLCacheOptions | ExistingTTLCacheOptions = {}) {\r\n super(options);\r\n\r\n if ('cache' in options) {\r\n this.cache = options.cache;\r\n } else {\r\n this.cache = new TTLCache<string, any>({\r\n max: options.max,\r\n ttl: options.ttl ? options.ttl * 1000 : undefined,\r\n dispose: (value, key, reason) => this.onDispose(key, value, reason),\r\n });\r\n }\r\n }\r\n\r\n /** @internal */\r\n _get<T>(key: string): T | null {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const data = this.cache.get(key);\r\n\r\n return data === undefined ? null : data;\r\n }\r\n\r\n /** @internal */\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const ttl = options?.ttl;\r\n\r\n this.cache.set(key, value, {\r\n ttl: ttl ? ttl * 1000 : undefined,\r\n });\r\n }\r\n\r\n /** @internal */\r\n _delete(key: string): void {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n this.cache.delete(key);\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache } from '../../base/local.js';\r\n\r\nexport interface LocalMapCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying map.\r\n */\r\n map?: MapLike<string, any>;\r\n\r\n /**\r\n * The maximum size of the cache.\r\n * When not set, the cache can grow indefinitely.\r\n */\r\n max?: number;\r\n}\r\n\r\nexport interface MapLike<K, V> {\r\n get(key: K): V | undefined;\r\n set(key: K, value: V): void;\r\n delete(key: K): void;\r\n has(key: K): boolean;\r\n keys(): IterableIterator<K>;\r\n size: number;\r\n clear(): void;\r\n}\r\n\r\n/**\r\n * A simple in-memory cache implementation based on {@link Map}.\r\n *\r\n * It ignores expiration times, but a limit of cached items can be set.\r\n *\r\n * It implements a simple FIFO eviction policy:\r\n * Once the limit of items is reached, the first inserted keys will be purged.\r\n */\r\nexport class LocalMapCache extends BaseLocalCache {\r\n protected readonly map: MapLike<string, any>;\r\n protected max: number;\r\n\r\n constructor(options: LocalMapCacheOptions = {}) {\r\n super(options);\r\n this.map = options.map ?? new Map<string, any>();\r\n this.max = options.max ?? Infinity;\r\n }\r\n\r\n /** @internal */\r\n _get<T>(key: string): T | null {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const data = this.map.get(key);\r\n\r\n return data === undefined ? null : data;\r\n }\r\n\r\n /** @internal */\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const previousValue = this.map.get(key);\r\n\r\n if (this.map.size >= this.max && previousValue === undefined) {\r\n this.evict(1);\r\n }\r\n\r\n this.map.set(key, value);\r\n this.onDispose(key, previousValue, 'set');\r\n }\r\n\r\n /** @internal */\r\n _delete(key: string): void {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n const previousValue = this.map.get(key);\r\n this.map.delete(key);\r\n this.onDispose(key, previousValue, 'delete');\r\n }\r\n\r\n override async setMany(data: Record<string, any>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany]', 'data =', data);\r\n\r\n const entries = Object.entries(data);\r\n\r\n const newEntries = entries.filter(([key]) => !this.map.has(key)).length;\r\n\r\n if (this.map.size + newEntries > this.max) {\r\n this.evict(this.map.size + newEntries - this.max);\r\n }\r\n\r\n for (const [key, value] of entries) {\r\n const previousValue = this.map.get(key);\r\n this.map.set(key, value);\r\n this.onDispose(key, previousValue, 'set');\r\n }\r\n }\r\n\r\n clear(): void {\r\n this.logger?.debug(this.name, '[clear]');\r\n\r\n for (const key of this.map.keys()) {\r\n this.onDispose(key, this.map.get(key), 'delete');\r\n }\r\n\r\n this.map.clear();\r\n }\r\n\r\n protected override onDispose(key: string, value: any, reason?: string) {\r\n if (value !== undefined) {\r\n super.onDispose(key, value, reason);\r\n }\r\n }\r\n\r\n protected evict(length: number): void {\r\n const keys = this.map.keys();\r\n\r\n for (let i = 0; i < length; i++) {\r\n const key = keys.next();\r\n\r\n if (key.done) {\r\n break;\r\n }\r\n\r\n this.logger?.debug(this.name, '[evict]', 'key = ', key);\r\n\r\n const previousValue = this.map.get(key.value);\r\n this.map.delete(key.value);\r\n this.onDispose(key.value, previousValue, 'evict');\r\n }\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache, type LocalCacheInternal } from '../../base/local.js';\r\n\r\nexport interface WeakCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache. This must be an in-memory cache.\r\n */\r\n cache: BaseLocalCache;\r\n}\r\n\r\ntype WeakValue = { v: WeakRef<any>; w: true; } | { v: any; w: false; };\r\n\r\n/**\r\n * A cache layer that stores objects as weak references.\r\n *\r\n * When an object is garbage collected, its entry is automatically removed from the underlying cache.\r\n *\r\n * This implementation requires support for both `WeakRef` and `FinalizationRegistry`.\r\n *\r\n * @see https://caniuse.com/mdn-javascript_builtins_finalizationregistry\r\n * @see https://caniuse.com/mdn-javascript_builtins_weakref\r\n */\r\nexport class WeakCache extends BaseLocalCache {\r\n protected readonly cache: BaseLocalCache;\r\n protected readonly cacheInternal: LocalCacheInternal;\r\n protected readonly registry: FinalizationRegistry<string>;\r\n\r\n constructor(options: WeakCacheOptions) {\r\n super(options);\r\n this.cache = options.cache;\r\n this.cacheInternal = options.cache.internal;\r\n this.cacheInternal._addDisposeListener(this.onCacheDispose);\r\n this.registry = new FinalizationRegistry<string>(this.onGarbageCollect);\r\n }\r\n\r\n protected onGarbageCollect = (key: string) => this.cacheInternal._delete(key);\r\n\r\n protected onCacheDispose = (key: string, value: any, reason?: string) => {\r\n this.unregister(value);\r\n this.onDispose(key, this.unwrap(value), reason);\r\n };\r\n\r\n /** @internal */\r\n override _get<T>(key: string): T | null {\r\n return this.unwrap(this.cacheInternal._get<WeakValue>(key));\r\n }\r\n\r\n /** @internal */\r\n override _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.cacheInternal._set<WeakValue>(key, this.wrapAndRegister(key, value), options);\r\n }\r\n\r\n /** @internal */\r\n override _delete(key: string): void {\r\n this.unregisterByKey(key);\r\n this.cacheInternal._delete(key);\r\n }\r\n\r\n /** @internal */\r\n override _getMany<T>(keys: string[]): Record<string, T | null> {\r\n const data = this.cacheInternal._getMany<any>(keys);\r\n\r\n for (const key of keys) {\r\n data[key] = this.unwrap(data[key]);\r\n }\r\n\r\n return data;\r\n }\r\n\r\n /** @internal */\r\n override _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void {\r\n Object.keys(data).forEach(key => this.unregisterByKey(key));\r\n\r\n const wrappedData: Record<string, WeakValue> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n wrappedData[key] = this.wrapAndRegister(key, value);\r\n }\r\n\r\n this.cacheInternal._setMany<WeakValue>(wrappedData, options);\r\n }\r\n\r\n /** @internal */\r\n override _deleteMany(keys: string[]): void {\r\n keys.forEach(key => this.unregisterByKey(key));\r\n\r\n this.cacheInternal._deleteMany(keys);\r\n }\r\n\r\n override async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const wrappedLoad = async () => this.wrapAndRegister(key, await load());\r\n\r\n return this.unwrap<T>(await this.cache.getOrLoad<WeakValue>(key, wrappedLoad, options))!;\r\n }\r\n\r\n /**\r\n * Wraps the value in a WeakRef and registers it in the FinalizationRegistry if it's an object.\r\n *\r\n * @param key The key to reference the value in the FinalizationRegistry\r\n * @param value The value to wrap\r\n * @returns The wrapped value\r\n */\r\n protected wrapAndRegister(key: string, value: any): WeakValue {\r\n this.unregisterByKey(key);\r\n\r\n if (value !== null && typeof value === 'object') {\r\n this.registry.register(value, key);\r\n\r\n return { v: new WeakRef(value), w: true };\r\n }\r\n\r\n return { v: value, w: false };\r\n }\r\n\r\n /**\r\n * Unwraps the value from a WeakRef if it's an object.\r\n *\r\n * @param data The data to unwrap\r\n * @returns The unwrapped value\r\n */\r\n protected unwrap<T>(data: WeakValue | null): T | null {\r\n if (data === null) {\r\n return null;\r\n }\r\n\r\n if (data.w) {\r\n return data.v.deref() ?? null;\r\n }\r\n\r\n return data.v;\r\n }\r\n\r\n /**\r\n * Unregisters the value from the FinalizationRegistry if it's an object.\r\n *\r\n * @param value The value to unregister\r\n */\r\n protected unregister(value: WeakValue | null): void {\r\n if (value && value.w) {\r\n this.registry.unregister(value.v);\r\n }\r\n }\r\n\r\n /**\r\n * Unregisters the value associated with the given key from the FinalizationRegistry.\r\n *\r\n * @param key The key\r\n */\r\n protected unregisterByKey(key: string): void {\r\n this.unregister(this.cacheInternal._get<WeakValue>(key));\r\n }\r\n}\r\n","import { BaseLocalCache, type LocalCacheInternal } from '../../base/local.js';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface DeepCloningCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache. This must be an in-memory cache.\r\n */\r\n cache: BaseLocalCache;\r\n\r\n /**\r\n * The deep clone function to use.\r\n *\r\n * By default, it will try to use `structuredClone()` if available,\r\n * otherwise it will use a JSON.parse/stringify-based implementation.\r\n *\r\n * @param data The data to deep clone\r\n * @returns The cloned data\r\n */\r\n deepClone?: <T>(data: T) => T;\r\n}\r\n\r\n/**\r\n * A cache layer that deep clones data when reading and writing.\r\n *\r\n * This is useful when you mutate the objects retrieved from cache,\r\n * and you don't want them to also change in cache.\r\n *\r\n * Do not use this layer if you do not intend to mutate cached objects,\r\n * as the cloning process adds unnecessary overhead.\r\n */\r\nexport class DeepCloningCache extends BaseLocalCache {\r\n protected readonly cache: BaseLocalCache;\r\n protected readonly cacheInternal: LocalCacheInternal;\r\n protected deepClone: <T>(data: T) => T;\r\n\r\n constructor(options: DeepCloningCacheOptions) {\r\n super(options);\r\n\r\n this.cache = options.cache;\r\n this.cacheInternal = options.cache.internal;\r\n\r\n if (options.deepClone) {\r\n this.deepClone = options.deepClone;\r\n } else if (typeof structuredClone === 'function') {\r\n // Use structuredClone whenever available since it is faster than JSON\r\n this.deepClone = structuredClone;\r\n } else {\r\n // Since we already expect cached items to be JSON-serializable,\r\n // we can use this simple implementation (that is also pretty fast).\r\n this.deepClone = <T>(data: T): T => JSON.parse(JSON.stringify(data));\r\n }\r\n }\r\n\r\n protected _get<T>(key: string): T | null {\r\n return this.deepClone(this.cacheInternal._get(key));\r\n }\r\n\r\n protected _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.cacheInternal._set(key, this.deepClone(value), options);\r\n }\r\n\r\n protected _delete(key: string): void {\r\n this.cacheInternal._delete(key);\r\n }\r\n\r\n protected override _getMany<T>(keys: string[]): Record<string, T | null> {\r\n return this.deepClone(this.cacheInternal._getMany<T>(keys));\r\n }\r\n\r\n protected override _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void {\r\n this.cacheInternal._setMany(this.deepClone(data), options);\r\n }\r\n\r\n protected override _deleteMany(keys: string[]): void {\r\n this.cacheInternal._deleteMany(keys);\r\n }\r\n\r\n protected override _addDisposeListener(listener: any): void {\r\n this.cacheInternal._addDisposeListener(listener);\r\n }\r\n\r\n override async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const loadWrapped = async () => this.deepClone(await load());\r\n\r\n return this.deepClone(await this.cache.getOrLoad(key, loadWrapped, options));\r\n }\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\n/**\r\n * A cache implementation that does nothing.\r\n * It's useful for disabling cache and unit testing.\r\n *\r\n * @example\r\n * ```ts\r\n * const cache = isCacheEnabled ? new LocalTTLCache() : new NoOpCache();\r\n * ```\r\n */\r\nexport class NoOpCache implements ICache {\r\n constructor() {}\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n return null;\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return {};\r\n }\r\n\r\n getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n return load();\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {}\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {}\r\n\r\n async delete(key: string): Promise<void> {}\r\n async deleteMany(keys: string[]): Promise<void> {}\r\n\r\n}\r\n","import type { Redis } from 'ioredis';\r\nimport type { Redis as Valkey } from 'iovalkey';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface IORedisCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The ioredis or iovalkey client\r\n */\r\n client: Redis | Valkey;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the UNLINK command.\r\n *\r\n * {@link IORedisCache#delete} and {@link IORedisCache#deleteMany} will use UNLINK instead of DEL if this\r\n * option is set to `true`. This is recommended to improve the deletion performance.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 4.0.0 or above.\r\n *\r\n * @defaultValue true\r\n */\r\n isUNLINKSupported?: boolean;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the MSETEX command.\r\n *\r\n * {@link IORedisCache#setMany} will use MSETEX if this option is set to `true`.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 8.4.0 or above.\r\n * Valkey does not support this yet. (see https://github.com/valkey-io/valkey/issues/2592)\r\n *\r\n * @defaultValue false\r\n */\r\n isMSETEXSupported?: boolean;\r\n}\r\n\r\n/**\r\n * A Redis cache implementation using ioredis\r\n */\r\nexport class IORedisCache extends BaseCache {\r\n protected readonly client: Redis | Valkey;\r\n protected defaultTTL?: number;\r\n protected isUNLINKSupported: boolean;\r\n protected isMSETEXSupported: boolean;\r\n\r\n constructor(options: IORedisCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n this.isUNLINKSupported = options.isUNLINKSupported ?? true;\r\n this.isMSETEXSupported = options.isMSETEXSupported ?? false;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"GET\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"SET\" command...', 'key =', key);\r\n\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n const raw = JSON.stringify(value);\r\n\r\n if (ttl) {\r\n await this.client.set(key, raw, 'EX', ttl);\r\n } else {\r\n await this.client.set(key, raw);\r\n }\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[delete] Running \"UNLINK\" command...', 'key =', key);\r\n\r\n await this.client.unlink(key);\r\n } else {\r\n this.logger?.debug(this.name, '[delete] Running \"DEL\" command...', 'key =', key);\r\n\r\n await this.client.del(key);\r\n }\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"MGET\" command...', 'keys =', keys);\r\n\r\n const values = await this.client.mget(keys);\r\n\r\n const data: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n const value = values[i];\r\n\r\n data[keys[i]!] = value ? JSON.parse(value) : null;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n override async setMany(data: Record<string, any>, options?: SetCacheOptions): Promise<void> {\r\n if (!this.isMSETEXSupported) {\r\n return super.setMany(data, options);\r\n }\r\n\r\n this.logger?.debug(this.name, '[setMany] Running \"MSETEX\" command...', 'data =', data);\r\n\r\n const entries = Object.entries(data);\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n const raw = entries.flatMap(([key, value]) => [\r\n key,\r\n JSON.stringify(value),\r\n ]);\r\n\r\n await this.client.call('MSETEX', entries.length, ...raw, ...(ttl ? ['EX', ttl] : []));\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"UNLINK\" command...', 'keys =', keys);\r\n\r\n await this.client.unlink(keys);\r\n } else {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"DEL\" command...', 'keys =', keys);\r\n\r\n await this.client.del(keys);\r\n }\r\n }\r\n\r\n}\r\n","import type { RedisClientType, RedisClientPoolType, RedisClusterType, RedisSentinelType } from '@redis/client';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\ntype Redis = RedisClientType | RedisClientPoolType | RedisClusterType | RedisSentinelType;\r\n\r\nexport interface RedisCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The Redis client\r\n */\r\n client: RedisClientType | RedisClientPoolType | RedisClusterType | RedisSentinelType;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the UNLINK command.\r\n *\r\n * {@link RedisCache#delete} and {@link RedisCache#deleteMany} will use UNLINK instead of DEL if this\r\n * option is set to `true`. This is recommended to improve the deletion performance.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 4.0.0 or above.\r\n *\r\n * @defaultValue true\r\n */\r\n isUNLINKSupported?: boolean;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the MSETEX command.\r\n *\r\n * {@link RedisCache#setMany} will use MSETEX if this option is set to `true`.\r\n * This is recommended to improve the performance of setting multiple items.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 8.4.0 or above.\r\n * Valkey does not support this yet. (see https://github.com/valkey-io/valkey/issues/2592)\r\n *\r\n * @defaultValue false\r\n */\r\n isMSETEXSupported?: boolean;\r\n}\r\n\r\n/**\r\n * A Redis cache implementation using node-redis\r\n */\r\nexport class RedisCache extends BaseCache {\r\n protected readonly client: Redis;\r\n protected defaultTTL?: number;\r\n protected isUNLINKSupported: boolean;\r\n protected isMSETEXSupported: boolean;\r\n\r\n constructor(options: RedisCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n this.isUNLINKSupported = options.isUNLINKSupported ?? true;\r\n this.isMSETEXSupported = options.isMSETEXSupported ?? false;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"GET\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"SET\" command...', 'key =', key);\r\n\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n { expiration: ttl ? { type: 'EX', value: ttl } : undefined },\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[delete] Running \"UNLINK\" command...', 'key =', key);\r\n\r\n await this.client.unlink(key);\r\n } else {\r\n this.logger?.debug(this.name, '[delete] Running \"DEL\" command...', 'key =', key);\r\n\r\n await this.client.del(key);\r\n }\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"MGET\" command...', 'keys =', keys);\r\n\r\n const values = await this.client.mGet(keys);\r\n\r\n const data: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n const value = values[i];\r\n\r\n data[keys[i]!] = value ? JSON.parse(value) : null;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n override async setMany(data: Record<string, any>, options?: SetCacheOptions): Promise<void> {\r\n if (!this.isMSETEXSupported) {\r\n return super.setMany(data, options);\r\n }\r\n\r\n this.logger?.debug(this.name, '[setMany] Running \"MSETEX\" command...', 'data =', data);\r\n\r\n const raw: [string, string][] = [];\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n raw.push([key, JSON.stringify(value)]);\r\n }\r\n\r\n await this.client.mSetEx(\r\n raw,\r\n { expiration: ttl ? { type: 'EX', value: ttl } : undefined },\r\n );\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"UNLINK\" command...', 'keys =', keys);\r\n\r\n await this.client.unlink(keys);\r\n } else {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"DEL\" command...', 'keys =', keys);\r\n\r\n await this.client.del(keys);\r\n }\r\n }\r\n\r\n}\r\n","import { BaseCache } from '../../base/index.js';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport type { BaseClient, GlideClient, GlideClusterClient } from '@valkey/valkey-glide';\r\n\r\nexport interface ValkeyGlideCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The GLIDE client instance\r\n */\r\n client: GlideClient | GlideClusterClient | BaseClient;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n}\r\n\r\n/**\r\n * A Valkey cache implementation using @valkey/valkey-glide\r\n */\r\nexport class ValkeyGlideCache extends BaseCache {\r\n protected readonly client: BaseClient;\r\n protected defaultTTL?: number;\r\n\r\n constructor(options: ValkeyGlideCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"GET\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw.toString()) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"SET\" command...', 'key =', key);\r\n\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n { expiry: ttl ? { type: 'EX' as any, count: ttl } : undefined },\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Running \"UNLINK\" command...', 'key =', key);\r\n\r\n await this.client.unlink([key]);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"MGET\" command...', 'keys =', keys);\r\n\r\n const values = await this.client.mget(keys);\r\n\r\n const data: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n const value = values[i];\r\n\r\n data[keys[i]!] = value ? JSON.parse(value.toString()) : null;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"UNLINK\" command...', 'keys =', keys);\r\n\r\n await this.client.unlink(keys);\r\n }\r\n\r\n}\r\n","import type Memcache from 'memcache';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface MemcacheCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The Memcache client\r\n */\r\n client: Memcache;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n}\r\n\r\n/**\r\n * A Memcached cache implementation using Memcache\r\n */\r\nexport class MemcacheCache extends BaseCache {\r\n protected readonly client: Memcache;\r\n protected defaultTTL?: number;\r\n\r\n constructor(options: MemcacheCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"get\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"set\" command...', 'key =', key);\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n options?.ttl ?? this.defaultTTL,\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Running \"delete\" command...', 'key =', key);\r\n\r\n await this.client.delete(key);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"get\" command...', 'keys =', keys);\r\n\r\n const raw = await this.client.gets(keys);\r\n const data: Record<string, T | null> = {};\r\n\r\n raw.forEach((value, key) => {\r\n data[key] = value ? JSON.parse(value) : null;\r\n });\r\n\r\n return data;\r\n }\r\n}\r\n","import type { Client } from 'memjs';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface MemJSCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The memjs client\r\n */\r\n client: Client;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n}\r\n\r\n/**\r\n * A Memcached cache implementation using MemJS\r\n */\r\nexport class MemJSCache extends BaseCache {\r\n protected readonly client: Client;\r\n protected defaultTTL?: number;\r\n\r\n constructor(options: MemJSCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"get\" command...', 'key =', key);\r\n\r\n const { value } = await this.client.get(key);\r\n\r\n return value ? JSON.parse(value.toString('utf8')) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"set\" command...', 'key =', key);\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n {\r\n expires: options?.ttl ?? this.defaultTTL,\r\n },\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Running \"delete\" command...', 'key =', key);\r\n\r\n await this.client.delete(key);\r\n }\r\n\r\n}\r\n","import type { KVNamespace } from '@cloudflare/workers-types';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface WorkersKVCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The KV namespace (`env.NAMESPACE`)\r\n */\r\n kv: KVNamespace;\r\n\r\n /**\r\n * The amount of time in seconds that a KV result is cached in the global network location it is accessed from.\r\n *\r\n * Increasing this value can improve read performance at the cost of data being stale.\r\n *\r\n * @see https://developers.cloudflare.com/kv/api/read-key-value-pairs/#cachettl-parameter\r\n */\r\n edgeCacheTTL?: number;\r\n}\r\n\r\n/**\r\n * A Cloudflare Workers KV cache implementation.\r\n */\r\nexport class WorkersKVCache extends BaseCache {\r\n protected readonly kv: KVNamespace;\r\n protected edgeCacheTTL?: number;\r\n\r\n constructor(options: WorkersKVCacheOptions) {\r\n super(options);\r\n this.kv = options.kv;\r\n this.edgeCacheTTL = options.edgeCacheTTL;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.kv.get<T>(key, { type: 'json', cacheTtl: this.edgeCacheTTL });\r\n }\r\n\r\n set<T>(key: string, value: T, options: SetCacheOptions = {}): Promise<void> {\r\n return this.kv.put(key, JSON.stringify(value), { expirationTtl: options.ttl });\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.kv.delete(key);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const data = await this.kv.get<T>(keys, { type: 'json', cacheTtl: this.edgeCacheTTL });\r\n\r\n return Object.fromEntries(data);\r\n }\r\n\r\n}\r\n","import { BaseCache } from '../../base/index.js';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport type Keyv from 'keyv';\r\n\r\nexport interface KeyvCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying key-value store\r\n */\r\n keyv: Keyv;\r\n}\r\n\r\nexport class KeyvCache extends BaseCache {\r\n protected readonly keyv: Keyv;\r\n\r\n constructor(options: KeyvCacheOptions) {\r\n super(options);\r\n this.keyv = options.keyv;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const result = await this.keyv.get<T>(key);\r\n\r\n return result === undefined ? null : result;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n await this.keyv.set(key, value, options?.ttl);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n await this.keyv.delete(key);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const data = await this.keyv.getMany(keys);\r\n const result: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n result[keys[i]] = data[i] === undefined ? null : data[i];\r\n }\r\n\r\n return result;\r\n }\r\n\r\n override async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n const ttl = options?.ttl;\r\n\r\n await this.keyv.setMany(\r\n Object.entries(data).map(([key, value]) => ({\r\n key,\r\n value,\r\n ttl,\r\n })),\r\n );\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n await this.keyv.deleteMany(keys);\r\n }\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface AsyncLazyCacheOptions {\r\n /**\r\n * A factory function that will be called to create the underlying cache when needed.\r\n */\r\n factory: () => Promise<ICache> | ICache;\r\n\r\n /**\r\n * Whether it should initialize only when needed.\r\n *\r\n * - When set to `true`, it will initialize the cache only when a method is called.\r\n * - When set to `false`, it will initialize the cache upon construction.\r\n *\r\n * @default `false`\r\n */\r\n lazy?: boolean;\r\n}\r\n\r\n/**\r\n * A cache layer that initializes the underlying cache asynchronously.\r\n *\r\n * This layer can be used to connect to an external cache with the cache methods already available.\r\n *\r\n * This layer can also be used to lazily initialize the cache only when it's actually needed.\r\n *\r\n * @example\r\n * ```ts\r\n * const cache = new AsyncCache({\r\n * factory: async () => {\r\n * const redisClient = await createClient({\r\n * url: \"redis://user:password@localhost:6380\",\r\n * });\r\n *\r\n * return new RedisCache({ client: redisClient });\r\n * },\r\n * lazy: true,\r\n * });\r\n *\r\n * cache.get(\"key\")\r\n * .then(result => console.log('redis was connected and read the key:', value));\r\n * ```\r\n */\r\nexport class AsyncLazyCache implements ICache {\r\n protected readonly factory: () => Promise<ICache> | ICache;\r\n protected cache: Promise<ICache> | null = null;\r\n\r\n constructor(options: AsyncLazyCacheOptions) {\r\n this.factory = options.factory;\r\n\r\n if (!options.lazy) {\r\n this.cache = Promise.resolve(this.factory());\r\n }\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n return (await this.resolveCache()).get<T>(key);\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n return (await this.resolveCache()).getOrLoad<T>(key, load, options);\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return (await this.resolveCache()).set<T>(key, value, options);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n return (await this.resolveCache()).delete(key);\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return (await this.resolveCache()).getMany<T>(keys);\r\n }\r\n\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n return (await this.resolveCache()).setMany<T>(data, options);\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n return (await this.resolveCache()).deleteMany(keys);\r\n }\r\n\r\n /**\r\n * Gets the underlying cache, initializing it if not already initialized.\r\n */\r\n public resolveCache(): Promise<ICache> {\r\n if (!this.cache) {\r\n this.cache = Promise.resolve(this.factory());\r\n }\r\n\r\n return this.cache;\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.d.ts';\r\nimport type { Logger } from '../../types/logger.js';\r\n\r\n/**\r\n * The options to construct the {@link CoalescingCache}\r\n */\r\nexport interface CoalescingCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n}\r\n\r\ninterface OngoingRequest {\r\n promise: Promise<any | null>;\r\n type: 'get' | 'getOrLoad';\r\n}\r\n\r\n/**\r\n * A cache strategy layer that deduplicates parallel requests into a single request.\r\n *\r\n * This strategy can prevent the Thundering Herd problem as all parallel requests will be coalesced into one.\r\n */\r\nexport class CoalescingCache implements ICache {\r\n protected readonly ongoingRequests: Map<string, OngoingRequest> = new Map();\r\n protected readonly cache: ICache;\r\n protected readonly name?: string;\r\n protected readonly logger?: Logger;\r\n\r\n constructor(options: CoalescingCacheOptions) {\r\n this.cache = options.cache;\r\n this.name = options.name;\r\n this.logger = options.logger;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n const ongoingRequest = this.ongoingRequests.get(key);\r\n\r\n if (ongoingRequest) {\r\n this.logger?.debug(this.name, '[get] Returning ongoing request...', 'key =', key);\r\n\r\n return ongoingRequest.promise;\r\n }\r\n\r\n this.logger?.debug(this.name, '[get] Reading from underlying cache...', 'key =', key);\r\n\r\n const promise = this.cache.get<T>(key);\r\n\r\n this.ongoingRequests.set(key, { promise, type: 'get' });\r\n\r\n return promise.finally(() => this.ongoingRequests.delete(key));\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const ongoingRequest = this.ongoingRequests.get(key);\r\n\r\n // When there's no ongoing requests, we'll do a new one\r\n if (!ongoingRequest) {\r\n this.logger?.debug(this.name, '[getOrLoad] Reading from the underlying cache...', 'key =', key);\r\n\r\n const promise = this.cache.getOrLoad(key, load, options);\r\n\r\n this.ongoingRequests.set(key, { promise, type: 'getOrLoad' });\r\n\r\n return promise.finally(() => this.ongoingRequests.delete(key));\r\n }\r\n\r\n // We'll await the ongoing request\r\n let request = await ongoingRequest.promise;\r\n\r\n // When the request is successful or the type is already getOrLoad, we'll just return it\r\n if (request !== null || ongoingRequest.type === 'getOrLoad') {\r\n this.logger?.debug(this.name, '[getOrLoad] Read from an ongoing request.', 'key =', key);\r\n\r\n return request;\r\n }\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Refreshing the cache...', 'key =', key);\r\n\r\n // Otherwise, we'll load it manually\r\n const promise = load();\r\n\r\n this.ongoingRequests.set(key, { promise, type: 'getOrLoad' });\r\n\r\n try {\r\n request = await promise;\r\n\r\n // When the request is successful, we'll store it in cache\r\n if (request !== null) {\r\n await this.cache.set(key, request, options);\r\n }\r\n } finally {\r\n // We'll only delete from \"ongoing requests\" when we finish saving it\r\n this.ongoingRequests.delete(key);\r\n }\r\n\r\n return request;\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const promise = this.cache.set<T>(key, value, options);\r\n\r\n this.ongoingRequests.set(key, {\r\n promise: promise.then(() => value),\r\n type: 'getOrLoad',\r\n });\r\n\r\n return promise.finally(() => this.ongoingRequests.delete(key));\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n try {\r\n this.ongoingRequests.set(key, {\r\n type: 'get',\r\n promise: Promise.resolve(null),\r\n });\r\n\r\n await this.cache.delete(key);\r\n } finally {\r\n this.ongoingRequests.delete(key);\r\n }\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const items: [string, Promise<T | null>][] = [];\r\n const remainingKeys: string[] = [];\r\n\r\n for (const key of keys) {\r\n const ongoingRequest = this.ongoingRequests.get(key);\r\n\r\n if (ongoingRequest) {\r\n items.push([key, ongoingRequest.promise]);\r\n } else {\r\n remainingKeys.push(key);\r\n }\r\n }\r\n\r\n this.logger?.debug(this.name, '[getMany]', items.length, 'ongoing requests found, reading', remainingKeys.length, 'resources.', 'keys =', keys);\r\n\r\n if (remainingKeys.length > 0) {\r\n const promise = this.cache.getMany<T>(remainingKeys);\r\n\r\n for (const key of remainingKeys) {\r\n const itemPromise = promise\r\n .then(data => data[key]!)\r\n .finally(() => this.ongoingRequests.delete(key));\r\n\r\n this.ongoingRequests.set(key, {\r\n promise: itemPromise,\r\n type: 'get',\r\n });\r\n\r\n items.push([key, itemPromise]);\r\n }\r\n }\r\n\r\n return Object.fromEntries(\r\n await Promise.all(\r\n items.map(async ([key, promise]) => [key, await promise])\r\n ),\r\n );\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany]', 'data =', data);\r\n\r\n const promise = this.cache.setMany(data, options);\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n this.ongoingRequests.set(key, {\r\n promise: promise.then(() => value).finally(() => this.ongoingRequests.delete(key)),\r\n type: 'getOrLoad',\r\n });\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany]', 'keys =', keys);\r\n\r\n try {\r\n for (const key of keys) {\r\n this.ongoingRequests.set(key, {\r\n type: 'get',\r\n promise: Promise.resolve(null),\r\n });\r\n }\r\n\r\n await this.cache.deleteMany(keys);\r\n } finally {\r\n for (const key of keys) {\r\n this.ongoingRequests.delete(key);\r\n }\r\n }\r\n\r\n }\r\n\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface JitteringCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL: number;\r\n\r\n /**\r\n * The maximum jitter (in seconds) to add to the TTL of cached items.\r\n */\r\n maxJitterTTL: number;\r\n}\r\n\r\n/**\r\n * A cache layer that adds a random jitter to the TTL of cached items to prevent cache stampedes.\r\n *\r\n * This layer is useful in scenarios where many cached items expire simultaneously, causing a sudden surge of requests to the underlying data source.\r\n */\r\nexport class JitteringCache implements ICache {\r\n protected readonly cache: ICache;\r\n protected defaultTTL: number;\r\n protected maxJitterTTL: number;\r\n\r\n constructor(options: JitteringCacheOptions) {\r\n this.cache = options.cache;\r\n this.defaultTTL = options.defaultTTL;\r\n this.maxJitterTTL = options.maxJitterTTL;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.cache.get<T>(key);\r\n }\r\n\r\n getOrLoad<T>(key: string, load: () => Promise<T>, options: SetCacheOptions = {}): Promise<T> {\r\n return this.cache.getOrLoad<T>(key, load, this.jitterTTL(options));\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.set<T>(key, value, this.jitterTTL(options));\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.cache.delete(key);\r\n }\r\n\r\n getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return this.cache.getMany(keys);\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.setMany(data, this.jitterTTL(options));\r\n }\r\n\r\n deleteMany(keys: string[]): Promise<void> {\r\n return this.cache.deleteMany(keys);\r\n }\r\n\r\n protected jitterTTL(options: SetCacheOptions = {}): SetCacheOptions {\r\n const ttl = options.ttl ?? this.defaultTTL;\r\n const jitter = Math.random() * this.maxJitterTTL;\r\n\r\n return {\r\n ...options,\r\n ttl: ttl + jitter,\r\n };\r\n }\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\ninterface BaseKeyTransformingCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n}\r\n\r\ninterface KeyTransformerFnCacheOptions extends BaseKeyTransformingCacheOptions {\r\n /**\r\n * The function that will be called with each key to transform it.\r\n * @param key The original key\r\n * @return The transformed key\r\n */\r\n transform: (key: string) => string;\r\n prefix?: never;\r\n suffix?: never;\r\n}\r\n\r\ninterface KeyAffixCacheOptions extends BaseKeyTransformingCacheOptions {\r\n /**\r\n * The prefix to add to keys\r\n */\r\n prefix?: string;\r\n\r\n /**\r\n * The suffix to add to keys\r\n */\r\n suffix?: string;\r\n}\r\n\r\nexport type KeyTransformingCacheOptions = KeyAffixCacheOptions | KeyTransformerFnCacheOptions;\r\n\r\n/**\r\n * A cache layer that changes keys before passing them to the underlying cache.\r\n *\r\n * This layer can be used to:\r\n * - Create namespaced caches, avoiding conflicts with shared cache servers.\r\n * - Add a version number, allowing schema changes without causing incompatibility.\r\n * - Implement any other key transformations, such as normalizing or hashing.\r\n */\r\nexport class KeyTransformingCache implements ICache {\r\n protected readonly cache: ICache;\r\n protected transform: (key: string) => string;\r\n\r\n constructor(options: KeyTransformingCacheOptions) {\r\n this.cache = options.cache;\r\n\r\n if ('transform' in options && typeof options.transform === 'function') {\r\n this.transform = options.transform;\r\n } else {\r\n const prefix = options.prefix || '';\r\n const suffix = options.suffix || '';\r\n this.transform = (key: string) => `${prefix}${key}${suffix}`;\r\n }\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.cache.get<T>(this.transform(key));\r\n }\r\n\r\n getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n return this.cache.getOrLoad(this.transform(key), load, options);\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.set(this.transform(key), value, options);\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.cache.delete(this.transform(key));\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const transformedKeys = keys.map(key => this.transform(key));\r\n const data = await this.cache.getMany<T>(transformedKeys);\r\n\r\n return Object.fromEntries(\r\n Object.entries(data).map(([transformedKey, value]) => [\r\n keys[transformedKeys.indexOf(transformedKey)],\r\n value,\r\n ]),\r\n );\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.setMany(\r\n Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [this.transform(key), value]),\r\n ),\r\n options,\r\n )\r\n }\r\n\r\n deleteMany(keys: string[]): Promise<void> {\r\n return this.cache.deleteMany(keys.map(key => this.transform(key)));\r\n }\r\n}\r\n","import type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.js';\r\nimport type { Logger } from '../../types/logger.js';\r\n\r\n/**\r\n * The options to create the {@link SWRCache}\r\n */\r\nexport interface SWRCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL: number;\r\n\r\n /**\r\n * The additional time in seconds to keep the resource stored, but consider it as stale\r\n */\r\n staleTTL: number;\r\n}\r\n\r\ninterface CachedItem<T> {\r\n data: T;\r\n expiresAt: number;\r\n}\r\n\r\n/**\r\n * A cache strategy that returns stale resources immediately while it refreshes the cache in background.\r\n *\r\n * This is an implementation of the Stale-While-Revalidate algorithm.\r\n *\r\n * This strategy is only effective when calling {@link ICache#getOrLoad}.\r\n */\r\nexport class SWRCache implements ICache {\r\n protected readonly revalidating: Map<string, Promise<any>> = new Map<string, Promise<any>>();\r\n protected readonly cache: ICache;\r\n protected readonly name?: string;\r\n protected readonly logger?: Logger;\r\n protected defaultTTL: number;\r\n protected staleTTL: number;\r\n\r\n constructor(options: SWRCacheOptions) {\r\n this.cache = options.cache;\r\n this.name = options.name;\r\n this.logger = options.logger;\r\n this.defaultTTL = options.defaultTTL;\r\n this.staleTTL = options.staleTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const item = await this.cache.get<CachedItem<T>>(key);\r\n\r\n return item ? item.data : null;\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options: SetCacheOptions = {}): Promise<T> {\r\n this.logger?.debug(this.name, '[getOrLoad]', 'key =', key);\r\n\r\n const ttl = options.ttl || this.defaultTTL;\r\n const cacheOptions = {\r\n ...options,\r\n ttl: ttl + this.staleTTL,\r\n };\r\n\r\n const loadItem = async (): Promise<CachedItem<T>> => ({\r\n data: await load(),\r\n expiresAt: Date.now() + ttl * 1000,\r\n });\r\n\r\n const item = await this.cache.getOrLoad<CachedItem<T>>(key, loadItem, cacheOptions);\r\n\r\n // The item is stale, we'll revalidate in background\r\n if (item && item.expiresAt < Date.now() && !this.revalidating.has(key)) {\r\n this.logger?.debug(this.name, '[getOrLoad] Refreshing stale resource in background...', 'key =', key);\r\n\r\n const promise = loadItem()\r\n .then(newItem => this.cache.set(key, newItem, cacheOptions))\r\n .finally(() => this.revalidating.delete(key));\r\n\r\n this.revalidating.set(key, promise);\r\n }\r\n\r\n return item.data;\r\n }\r\n\r\n set<T>(key: string, value: T, options: SetCacheOptions = {}): Promise<void> {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const ttl = options.ttl || this.defaultTTL;\r\n const item: CachedItem<T> = {\r\n data: value,\r\n expiresAt: Date.now() + ttl * 1000,\r\n };\r\n const cacheOptions = {\r\n ...options,\r\n ttl: ttl + this.staleTTL,\r\n };\r\n\r\n return this.cache.set(key, item, cacheOptions);\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n return this.cache.delete(key);\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany]', 'keys =', keys);\r\n\r\n const data = await this.cache.getMany<CachedItem<T>>(keys);\r\n const items: Record<string, T | null> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n items[key] = value ? value.data : null;\r\n }\r\n\r\n return items;\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options: SetCacheOptions = {}): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany]', 'data =', data);\r\n\r\n const ttl = options.ttl || this.defaultTTL;\r\n const items: Record<string, CachedItem<T>> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n items[key] = {\r\n data: value,\r\n expiresAt: Date.now() + ttl * 1000,\r\n };\r\n }\r\n\r\n return this.cache.setMany(items, {\r\n ...options,\r\n ttl: ttl + this.staleTTL,\r\n });\r\n }\r\n\r\n deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany]', 'keys =', keys);\r\n\r\n return this.cache.deleteMany(keys);\r\n }\r\n\r\n}\r\n","import { BaseCache } from '../../base/index.js';\r\nimport type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface TieredCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The list of tiers in order of priority.\r\n *\r\n * The first item represents the \"hot\" cache while the last one represents a \"cold\" cache.\r\n */\r\n tiers: CacheTier[];\r\n}\r\n\r\nexport interface CacheTier {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n\r\n /**\r\n * The options that will be passed to {@link ICache#getOrLoad}, {@link ICache#set} and {@link ICache#setMany}.\r\n */\r\n options?: SetCacheOptions;\r\n}\r\n\r\n/**\r\n * A cache strategy layer that implements multi-level caching\r\n *\r\n * The objective of a tiered cache is to minimize latency while still having the benefits of a larger, shared cache.\r\n * This is done by having the first tier being an in-memory cache (such as {@link LocalTTLCache}) that stores a small amount of items with a short TTL,\r\n * and the second tier being an external cache (such as {@link RedisCache}) that stores a lot more items and may have a longer TTL.\r\n *\r\n * This strategy is similarly known as Cache Hierarchy, CPU cache or L1/L2/L3 cache.\r\n */\r\nexport class TieredCache extends BaseCache {\r\n protected readonly tiers: CacheTier[];\r\n\r\n constructor(options: TieredCacheOptions) {\r\n super(options);\r\n this.tiers = options.tiers;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const next = (i: number): Promise<T | null> => {\r\n this.logger?.debug(this.name, '[get] Reading from tier =', i, 'key =', key);\r\n\r\n const tier = this.tiers[i]!;\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n if (isLastTier) {\r\n return tier.cache.get<T>(key);\r\n }\r\n\r\n return tier.cache.getOrLoad(key, () => next(i + 1), tier.options);\r\n };\r\n\r\n return next(0);\r\n }\r\n\r\n override async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const next = (i: number): Promise<T> => {\r\n this.logger?.debug(this.name, '[getOrLoad] Reading from tier =', i, 'key =', key);\r\n\r\n const tier = this.tiers[i]!;\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n if (isLastTier) {\r\n return tier.cache.getOrLoad(key, load, options || tier.options);\r\n }\r\n\r\n return tier.cache.getOrLoad(key, () => next(i + 1), tier.options);\r\n };\r\n\r\n return next(0);\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Writing to all tiers in parallel...', 'key =', key);\r\n\r\n await Promise.all(\r\n this.tiers.map((tier, i) => {\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n return tier.cache.set(key, value, isLastTier ? (options || tier.options) : tier.options);\r\n }),\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Deleting from all tiers in parallel...', 'key =', key);\r\n\r\n await Promise.all(\r\n this.tiers.map(tier => tier.cache.delete(key)),\r\n );\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const next = async (i: number, remainingKeys: string[]): Promise<Record<string, T | null>> => {\r\n this.logger?.debug(this.name, '[getMany] Reading from tier =', i, 'keys =', keys);\r\n\r\n const tier = this.tiers[i]!;\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n const items = await tier.cache.getMany<T>(remainingKeys);\r\n\r\n remainingKeys = Object.entries(items)\r\n .filter(([, value]) => value === null || value === undefined)\r\n .map(([key]) => key);\r\n\r\n if (isLastTier || remainingKeys.length === 0) {\r\n return items;\r\n }\r\n\r\n const nextItems = await next(i + 1, remainingKeys);\r\n\r\n const backfillItems = Object.entries(nextItems)\r\n .filter(([, value]) => value !== null && value !== undefined);\r\n\r\n if (backfillItems.length > 0) {\r\n await tier.cache.setMany(Object.fromEntries(backfillItems), tier.options);\r\n }\r\n\r\n return {\r\n ...items,\r\n ...nextItems,\r\n };\r\n };\r\n\r\n return next(0, keys);\r\n }\r\n\r\n override async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany] Writing to all tiers in parallel...', 'data =', data);\r\n\r\n await Promise.all(\r\n this.tiers.map((tier, i) => {\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n return tier.cache.setMany(data, isLastTier ? (options || tier.options) : tier.options);\r\n }),\r\n );\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany] Deleting from all tiers in parallel...', 'keys =', keys);\r\n\r\n await Promise.all(\r\n this.tiers.map(tier => tier.cache.deleteMany(keys)),\r\n );\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.js';\r\nimport type { Logger } from '../../types/logger.js';\r\n\r\nexport interface MetricsCollectingCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n}\r\n\r\ninterface CacheCountMetrics {\r\n /** Amount of times the cache didn't have the requested resource */\r\n missCount: number;\r\n\r\n /** The amount of times the cache returned the requested resource */\r\n hitCount: number;\r\n\r\n /** The amount of times the cache was refreshed (the `load` function was called in {@link ICache#getOrLoad}) */\r\n loadCount: number;\r\n\r\n /** The amount of times the cache was updated */\r\n setCount: number;\r\n\r\n /** The amount of times a cached resource was invalidated */\r\n deleteCount: number;\r\n}\r\n\r\ninterface CacheTimeMetrics {\r\n /** Average time taken to verify that the cache didn't have a single requested resource (in milliseconds) */\r\n missTime: number;\r\n\r\n /** Average time taken to return a single requested resource from cache (in milliseconds) */\r\n hitTime: number;\r\n\r\n /** Average time taken to load a single resource from source (in milliseconds) */\r\n loadTime: number;\r\n\r\n /** Average time taken to update a single resource from cache (in milliseconds) */\r\n setTime: number;\r\n\r\n /** Average time taken to invalidate a single resource from cache (in milliseconds) */\r\n deleteTime: number;\r\n}\r\n\r\nexport type CacheMetrics = CacheCountMetrics & CacheTimeMetrics;\r\n\r\n/**\r\n * A cache layer that collects metrics from each cache call.\r\n *\r\n * This can be useful to measure the cache effectiveness\r\n */\r\nexport class MetricsCollectingCache implements ICache {\r\n protected readonly cache: ICache;\r\n protected readonly logger?: Logger;\r\n protected name?: string;\r\n\r\n protected countMetrics: CacheCountMetrics = {\r\n missCount: 0,\r\n hitCount: 0,\r\n loadCount: 0,\r\n setCount: 0,\r\n deleteCount: 0,\r\n };\r\n protected totalTimeMetrics: CacheTimeMetrics = {\r\n missTime: 0,\r\n hitTime: 0,\r\n loadTime: 0,\r\n setTime: 0,\r\n deleteTime: 0,\r\n };\r\n\r\n constructor(options: MetricsCollectingCacheOptions) {\r\n this.cache = options.cache;\r\n this.logger = options.logger;\r\n this.name = options.name;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const startAt = performance.now();\r\n\r\n const data = await this.cache.get<T>(key);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n if (data === null) {\r\n this.countMetrics.missCount++;\r\n this.totalTimeMetrics.missTime += time;\r\n\r\n this.logger?.debug(this.name, '[get] Cache miss.', 'key =', key, 'timeMS =', time);\r\n } else {\r\n this.countMetrics.hitCount++;\r\n this.totalTimeMetrics.hitTime += time;\r\n\r\n this.logger?.debug(this.name, '[get] Cache hit.', 'key =', key, 'timeMS =', time);\r\n }\r\n\r\n return data;\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n let didTriggerLoad: boolean = false;\r\n let loadFinishAt: number = 0;\r\n\r\n const loadMiddleware = (): Promise<T> => {\r\n const missFinishAt = performance.now();\r\n\r\n this.countMetrics.missCount++;\r\n this.totalTimeMetrics.missTime += missFinishAt - startAt;\r\n\r\n didTriggerLoad = true;\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Cache refresh.', 'key =', key);\r\n\r\n const loadStartAt = performance.now();\r\n\r\n return load().finally(() => {\r\n loadFinishAt = performance.now();\r\n\r\n this.countMetrics.loadCount++;\r\n this.totalTimeMetrics.loadTime += loadFinishAt - loadStartAt;\r\n });\r\n };\r\n\r\n let startAt = performance.now();\r\n\r\n const data = await this.cache.getOrLoad<T>(key, loadMiddleware, options);\r\n\r\n if (!didTriggerLoad) {\r\n const hitFinishedAt = performance.now();\r\n\r\n this.countMetrics.hitCount++;\r\n this.totalTimeMetrics.hitTime += hitFinishedAt - startAt;\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Cache hit.', 'key =', key);\r\n } else {\r\n const setFinishAt = performance.now();\r\n\r\n this.countMetrics.setCount++;\r\n this.totalTimeMetrics.setTime += setFinishAt - loadFinishAt;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.set(key, value, options);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n this.countMetrics.setCount++;\r\n this.totalTimeMetrics.setTime += time;\r\n\r\n this.logger?.debug(this.name, '[set] Cache set.', 'key =', key, 'timeMS =', time);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.delete(key);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n this.countMetrics.deleteCount++;\r\n this.totalTimeMetrics.deleteTime += time;\r\n\r\n this.logger?.debug(this.name, '[delete] Cache delete.', 'key =', key, 'timeMS =', time);\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const startAt = performance.now();\r\n\r\n const data = await this.cache.getMany<T>(keys);\r\n\r\n const time = performance.now() - startAt;\r\n const timePerKey = time / keys.length;\r\n\r\n const miss = keys.filter(key => data[key] === undefined || data[key] === null).length;\r\n const hits = keys.length - miss;\r\n\r\n this.countMetrics.missCount += miss;\r\n this.countMetrics.hitCount += hits;\r\n this.totalTimeMetrics.missTime += miss * timePerKey;\r\n this.totalTimeMetrics.hitTime += hits * timePerKey;\r\n\r\n this.logger?.debug(this.name, '[getMany]', 'hits =', hits, 'misses = ', miss, 'timeMS =', time);\r\n\r\n return data;\r\n }\r\n\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.setMany(data, options);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n const sets = Object.keys(data).length;\r\n\r\n this.countMetrics.setCount += sets;\r\n this.totalTimeMetrics.setTime += time;\r\n\r\n this.logger?.debug(this.name, '[setMany]', 'sets =', sets, 'timeMS =', time);\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.deleteMany(keys);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n this.countMetrics.deleteCount += keys.length;\r\n this.totalTimeMetrics.deleteTime += time;\r\n\r\n this.logger?.debug(this.name, '[deleteMany]', 'deletes =', keys.length, 'timeMS =', time);\r\n }\r\n\r\n getMetrics(): CacheMetrics {\r\n const count = this.countMetrics;\r\n const time = this.totalTimeMetrics;\r\n\r\n return {\r\n ...count,\r\n missTime: count.missCount === 0 ? 0 : time.missTime / count.missCount,\r\n hitTime: count.hitCount === 0 ? 0 : time.hitTime / count.hitCount,\r\n loadTime: count.loadCount === 0 ? 0 : time.loadTime / count.loadCount,\r\n setTime: count.setCount === 0 ? 0 : time.setTime / count.setCount,\r\n deleteTime: count.deleteCount === 0 ? 0 : time.deleteTime / count.deleteCount,\r\n };\r\n }\r\n\r\n resetMetrics(): void {\r\n this.countMetrics = {\r\n missCount: 0,\r\n hitCount: 0,\r\n loadCount: 0,\r\n setCount: 0,\r\n deleteCount: 0,\r\n };\r\n this.totalTimeMetrics = {\r\n missTime: 0,\r\n hitTime: 0,\r\n loadTime: 0,\r\n setTime: 0,\r\n deleteTime: 0,\r\n };\r\n\r\n this.logger?.debug(this.name, '[resetMetrics]');\r\n }\r\n\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["options","wrappedData: Record<string, WeakValue>","data: Record<string, T | null>","data: Record<string, T | null>","raw: [string, string][]","data: Record<string, T | null>","data: Record<string, T | null>","data: Record<string, T | null>","result: Record<string, T | null>","promise","items: [string, Promise<T | null>][]","remainingKeys: string[]","loadResult: T","item: CachedItem<T>","items: Record<string, T | null>","items: Record<string, CachedItem<T>>","didTriggerLoad: boolean","loadFinishAt: number"],"sources":["../src/base/index.ts","../src/base/local.ts","../src/local/lru/index.ts","../src/local/ttl/index.ts","../src/local/map/index.ts","../src/local/weak/index.ts","../src/local/cloning/index.ts","../src/local/noop/index.ts","../src/remote/ioredis/index.ts","../src/remote/redis/index.ts","../src/remote/valkey-glide/index.ts","../src/remote/memcache/index.ts","../src/remote/memjs/index.ts","../src/remote/workers-kv/index.ts","../src/remote/hazelcast/index.ts","../src/remote/keyv/index.ts","../src/layers/async-lazy/index.ts","../src/layers/coalescing/index.ts","../src/layers/fail-safe/index.ts","../src/layers/jittering/index.ts","../src/layers/key-transforming/index.ts","../src/layers/swr/index.ts","../src/layers/tiered/index.ts","../src/layers/metrics/index.ts"],"sourcesContent":["import type { BaseCacheOptions, ICache, SetCacheOptions } from '../types/cache.js';\r\nimport type { Logger } from '../types/logger.js';\r\n\r\n/**\r\n * The base implementation of a cache.\r\n *\r\n * This class only requires subclasses to implement {@link ICache#get}, {@link ICache#set} and {@link ICache#delete}.\r\n * All other methods fall back into these three.\r\n */\r\nexport abstract class BaseCache implements ICache {\r\n protected readonly name?: string;\r\n protected readonly logger?: Logger;\r\n\r\n protected constructor(options: BaseCacheOptions) {\r\n this.name = options.name;\r\n this.logger = options.logger;\r\n }\r\n\r\n abstract get<T>(key: string): Promise<T | null>;\r\n\r\n abstract set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;\r\n\r\n abstract delete(key: string): Promise<void>;\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n let data = await this.get<T>(key);\r\n\r\n if (data !== null) {\r\n this.logger?.debug(this.name, '[getOrLoad] Returning from cache.', 'key =', key);\r\n\r\n return data;\r\n }\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Refreshing the cache...', 'key =', key);\r\n\r\n data = await load();\r\n\r\n await this.set(key, data, options);\r\n\r\n return data;\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Reading all keys in parallel...', 'keys =', keys);\r\n\r\n return Object.fromEntries(\r\n await Promise.all(\r\n keys.map(async key => [key, await this.get<any>(key)]),\r\n ),\r\n );\r\n }\r\n\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany] Writing all keys in parallel...', 'data =', data);\r\n\r\n await Promise.all(\r\n Object.entries(data).map(([key, value]) =>\r\n this.set(key, value, options)\r\n ),\r\n );\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany] Deleting all keys in parallel...', 'keys =', keys);\r\n\r\n await Promise.all(\r\n keys.map(key => this.delete(key)),\r\n );\r\n }\r\n\r\n}\r\n","import type { SetCacheOptions } from '../types/cache.js';\r\nimport { BaseCache } from './index.js';\r\n\r\ntype LocalCacheDisposeListener<T = any> = (key: string, value: T, reason?: string) => void;\r\n\r\n/**\r\n * Internal methods for synchronous cache operations.\r\n * @experimental\r\n */\r\nexport interface LocalCacheInternal {\r\n _get<T>(key: string): T | null;\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void;\r\n _delete(key: string): void;\r\n _getMany<T>(keys: string[]): Record<string, T | null>;\r\n _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void;\r\n _deleteMany(keys: string[]): void;\r\n _addDisposeListener(listener: LocalCacheDisposeListener): void;\r\n}\r\n\r\nexport abstract class BaseLocalCache extends BaseCache {\r\n protected disposeListeners: LocalCacheDisposeListener[] = [];\r\n\r\n /**\r\n * Reads the cached resource from a key (synchronous version)\r\n */\r\n protected abstract _get<T>(key: string): T | null;\r\n\r\n /**\r\n * Writes a resource into cache (synchronous version)\r\n */\r\n protected abstract _set<T>(key: string, value: T, options?: SetCacheOptions): void;\r\n\r\n /**\r\n * Deletes a cached resource by a key. (synchronous version)\r\n */\r\n protected abstract _delete(key: string): void;\r\n\r\n /**\r\n * Reads cached resources by their keys. (synchronous version)\r\n */\r\n protected _getMany<T>(keys: string[]): Record<string, T | null> {\r\n return Object.fromEntries(\r\n keys.map(key => [key, this._get<T>(key)])\r\n );\r\n }\r\n\r\n /**\r\n * Writes resources into cache. (synchronous version)\r\n */\r\n protected _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void {\r\n for (const [key, value] of Object.entries(data)) {\r\n this._set<T>(key, value, options);\r\n }\r\n }\r\n\r\n /**\r\n * Deletes many cached resources by their keys. (synchronous version)\r\n */\r\n protected _deleteMany(keys: string[]): void {\r\n for (const key of keys) {\r\n this._delete(key);\r\n }\r\n }\r\n\r\n /**\r\n * Adds a listener that will be called when a cached item is disposed.\r\n *\r\n * @param listener The listener function to add.\r\n */\r\n protected _addDisposeListener(listener: LocalCacheDisposeListener): void {\r\n this.disposeListeners.push(listener);\r\n }\r\n\r\n /**\r\n * Gets access to the internal synchronous methods.\r\n * @experimental\r\n */\r\n get internal(): LocalCacheInternal {\r\n return this as unknown as LocalCacheInternal;\r\n }\r\n\r\n /** @sealed **/\r\n get<T>(key: string): Promise<T | null> {\r\n return Promise.resolve(this._get<T>(key));\r\n }\r\n\r\n /** @sealed **/\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this._set(key, value, options);\r\n return Promise.resolve();\r\n }\r\n\r\n /** @sealed **/\r\n delete(key: string): Promise<void> {\r\n this._delete(key);\r\n return Promise.resolve();\r\n }\r\n\r\n /** @sealed **/\r\n override getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return Promise.resolve(this._getMany(keys));\r\n }\r\n\r\n /** @sealed **/\r\n override setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this._setMany(data, options);\r\n return Promise.resolve();\r\n }\r\n\r\n /** @sealed **/\r\n override deleteMany(keys: string[]): Promise<void> {\r\n this._deleteMany(keys);\r\n return Promise.resolve();\r\n }\r\n\r\n protected onDispose(key: string, value: any, reason?: string): void {\r\n for (const listener of this.disposeListeners) {\r\n listener(key, value, reason);\r\n }\r\n }\r\n\r\n}\r\n","import { LRUCache } from 'lru-cache';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache } from '../../base/local.js';\r\n\r\nexport interface ExistingLRUCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The existing instance of a LRUCache.\r\n */\r\n cache: LRUCache<string, any, () => Promise<any>>;\r\n\r\n /**\r\n * Whether it should call {@link LRUCache#fetch} when `getOrLoad` is called.\r\n *\r\n * For that, {@link LRUCache#fetchMethod} needs to call the context function:\r\n * ```ts\r\n * new LRUCache<string, any, () => Promise<any>>({\r\n * fetchMethod: (_key, _staleValue, options) => options.context(),\r\n * });\r\n * ```\r\n */\r\n shouldUseFetch?: boolean;\r\n}\r\n\r\nexport interface LocalLRUCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The default Time to Live (in seconds)\r\n */\r\n ttl?: number;\r\n\r\n /**\r\n * The maximum amount of items stored\r\n */\r\n max?: number;\r\n}\r\n\r\n/**\r\n * An in-memory cache implementation of a Least-Recently-Used cache eviction algorithm.\r\n *\r\n * It allows setting an expiration time and a limit of cached items.\r\n *\r\n * Once the limit of items is reached, the least recently used items will be purged.\r\n */\r\nexport class LocalLRUCache extends BaseLocalCache {\r\n protected readonly cache: LRUCache<string, any, () => Promise<any>>;\r\n protected shouldUseFetch?: boolean;\r\n\r\n constructor(options: LocalLRUCacheOptions | ExistingLRUCacheOptions = {}) {\r\n super(options);\r\n\r\n if ('cache' in options) {\r\n this.cache = options.cache;\r\n this.shouldUseFetch = options.shouldUseFetch;\r\n } else {\r\n this.cache = new LRUCache<string, any, () => Promise<any>>({\r\n ttl: options.ttl ? options.ttl * 1000 : undefined,\r\n max: options.max || 10_000,\r\n ttlAutopurge: false,\r\n fetchMethod: (_key, _staleValue, options) => options.context(),\r\n disposeAfter: (value, key, reason) => this.onDispose(key, value, reason),\r\n });\r\n this.shouldUseFetch = true;\r\n }\r\n }\r\n\r\n /** @internal */\r\n _get<T>(key: string): T | null {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const data = this.cache.get(key);\r\n\r\n return data === undefined ? null : data;\r\n }\r\n\r\n /** @internal */\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const ttl = options?.ttl;\r\n\r\n this.cache.set(key, value, {\r\n ttl: ttl ? ttl * 1000 : undefined,\r\n });\r\n }\r\n\r\n /** @internal */\r\n _delete(key: string): void {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n this.cache.delete(key);\r\n }\r\n\r\n override getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n if (!this.shouldUseFetch) {\r\n return super.getOrLoad(key, load, options);\r\n }\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Running LRUCache\\'s fetch...', 'key =', key);\r\n\r\n const ttl = options?.ttl;\r\n\r\n return this.cache.fetch(key, {\r\n context: load,\r\n ttl: ttl ? ttl * 1000 : undefined,\r\n });\r\n }\r\n\r\n}\r\n","import { TTLCache } from '@isaacs/ttlcache';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache } from '../../base/local.js';\r\n\r\nexport interface ExistingTTLCacheOptions extends BaseCacheOptions {\r\n /**\r\n * Existing instance of a TTLCache\r\n */\r\n cache: TTLCache<string, any>;\r\n}\r\n\r\nexport interface LocalTTLCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The default Time to Live (in seconds)\r\n */\r\n ttl?: number;\r\n\r\n /**\r\n * The maximum amount of items stored\r\n */\r\n max?: number;\r\n}\r\n\r\n/**\r\n * An in-memory cache implementation that allows setting an expiration time and a limit of cached items.\r\n *\r\n * Once the limit of items is reached, the soonest expiring items will be purged.\r\n */\r\nexport class LocalTTLCache extends BaseLocalCache {\r\n protected readonly cache: TTLCache<string, any>;\r\n\r\n constructor(options: LocalTTLCacheOptions | ExistingTTLCacheOptions = {}) {\r\n super(options);\r\n\r\n if ('cache' in options) {\r\n this.cache = options.cache;\r\n } else {\r\n this.cache = new TTLCache<string, any>({\r\n max: options.max,\r\n ttl: options.ttl ? options.ttl * 1000 : undefined,\r\n dispose: (value, key, reason) => this.onDispose(key, value, reason),\r\n });\r\n }\r\n }\r\n\r\n /** @internal */\r\n _get<T>(key: string): T | null {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const data = this.cache.get(key);\r\n\r\n return data === undefined ? null : data;\r\n }\r\n\r\n /** @internal */\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const ttl = options?.ttl;\r\n\r\n this.cache.set(key, value, {\r\n ttl: ttl ? ttl * 1000 : undefined,\r\n });\r\n }\r\n\r\n /** @internal */\r\n _delete(key: string): void {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n this.cache.delete(key);\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache } from '../../base/local.js';\r\n\r\nexport interface LocalMapCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying map.\r\n */\r\n map?: MapLike<string, any>;\r\n\r\n /**\r\n * The maximum size of the cache.\r\n * When not set, the cache can grow indefinitely.\r\n */\r\n max?: number;\r\n}\r\n\r\nexport interface MapLike<K, V> {\r\n get(key: K): V | undefined;\r\n set(key: K, value: V): void;\r\n delete(key: K): void;\r\n has(key: K): boolean;\r\n keys(): IterableIterator<K>;\r\n size: number;\r\n clear(): void;\r\n}\r\n\r\n/**\r\n * A simple in-memory cache implementation based on {@link Map}.\r\n *\r\n * It ignores expiration times, but a limit of cached items can be set.\r\n *\r\n * It implements a simple FIFO eviction policy:\r\n * Once the limit of items is reached, the first inserted keys will be purged.\r\n */\r\nexport class LocalMapCache extends BaseLocalCache {\r\n protected readonly map: MapLike<string, any>;\r\n protected max: number;\r\n\r\n constructor(options: LocalMapCacheOptions = {}) {\r\n super(options);\r\n this.map = options.map ?? new Map<string, any>();\r\n this.max = options.max ?? Infinity;\r\n }\r\n\r\n /** @internal */\r\n _get<T>(key: string): T | null {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const data = this.map.get(key);\r\n\r\n return data === undefined ? null : data;\r\n }\r\n\r\n /** @internal */\r\n _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const previousValue = this.map.get(key);\r\n\r\n if (this.map.size >= this.max && previousValue === undefined) {\r\n this.evict(1);\r\n }\r\n\r\n this.map.set(key, value);\r\n this.onDispose(key, previousValue, 'set');\r\n }\r\n\r\n /** @internal */\r\n _delete(key: string): void {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n const previousValue = this.map.get(key);\r\n this.map.delete(key);\r\n this.onDispose(key, previousValue, 'delete');\r\n }\r\n\r\n override async setMany(data: Record<string, any>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany]', 'data =', data);\r\n\r\n const entries = Object.entries(data);\r\n\r\n const newEntries = entries.filter(([key]) => !this.map.has(key)).length;\r\n\r\n if (this.map.size + newEntries > this.max) {\r\n this.evict(this.map.size + newEntries - this.max);\r\n }\r\n\r\n for (const [key, value] of entries) {\r\n const previousValue = this.map.get(key);\r\n this.map.set(key, value);\r\n this.onDispose(key, previousValue, 'set');\r\n }\r\n }\r\n\r\n clear(): void {\r\n this.logger?.debug(this.name, '[clear]');\r\n\r\n for (const key of this.map.keys()) {\r\n this.onDispose(key, this.map.get(key), 'delete');\r\n }\r\n\r\n this.map.clear();\r\n }\r\n\r\n protected override onDispose(key: string, value: any, reason?: string) {\r\n if (value !== undefined) {\r\n super.onDispose(key, value, reason);\r\n }\r\n }\r\n\r\n protected evict(length: number): void {\r\n const keys = this.map.keys();\r\n\r\n for (let i = 0; i < length; i++) {\r\n const key = keys.next();\r\n\r\n if (key.done) {\r\n break;\r\n }\r\n\r\n this.logger?.debug(this.name, '[evict]', 'key = ', key);\r\n\r\n const previousValue = this.map.get(key.value);\r\n this.map.delete(key.value);\r\n this.onDispose(key.value, previousValue, 'evict');\r\n }\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseLocalCache, type LocalCacheInternal } from '../../base/local.js';\r\n\r\nexport interface WeakCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache. This must be an in-memory cache.\r\n */\r\n cache: BaseLocalCache;\r\n}\r\n\r\ntype WeakValue = { v: WeakRef<any>; w: true; } | { v: any; w: false; };\r\n\r\n/**\r\n * A cache layer that stores objects as weak references.\r\n *\r\n * When an object is garbage collected, its entry is automatically removed from the underlying cache.\r\n *\r\n * This implementation requires support for both `WeakRef` and `FinalizationRegistry`.\r\n *\r\n * @see https://caniuse.com/mdn-javascript_builtins_finalizationregistry\r\n * @see https://caniuse.com/mdn-javascript_builtins_weakref\r\n */\r\nexport class WeakCache extends BaseLocalCache {\r\n protected readonly cache: BaseLocalCache;\r\n protected readonly cacheInternal: LocalCacheInternal;\r\n protected readonly registry: FinalizationRegistry<string>;\r\n\r\n constructor(options: WeakCacheOptions) {\r\n super(options);\r\n this.cache = options.cache;\r\n this.cacheInternal = options.cache.internal;\r\n this.cacheInternal._addDisposeListener(this.onCacheDispose);\r\n this.registry = new FinalizationRegistry<string>(this.onGarbageCollect);\r\n }\r\n\r\n protected onGarbageCollect = (key: string) => this.cacheInternal._delete(key);\r\n\r\n protected onCacheDispose = (key: string, value: any, reason?: string) => {\r\n this.unregister(value);\r\n this.onDispose(key, this.unwrap(value), reason);\r\n };\r\n\r\n /** @internal */\r\n override _get<T>(key: string): T | null {\r\n return this.unwrap(this.cacheInternal._get<WeakValue>(key));\r\n }\r\n\r\n /** @internal */\r\n override _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.cacheInternal._set<WeakValue>(key, this.wrapAndRegister(key, value), options);\r\n }\r\n\r\n /** @internal */\r\n override _delete(key: string): void {\r\n this.unregisterByKey(key);\r\n this.cacheInternal._delete(key);\r\n }\r\n\r\n /** @internal */\r\n override _getMany<T>(keys: string[]): Record<string, T | null> {\r\n const data = this.cacheInternal._getMany<any>(keys);\r\n\r\n for (const key of keys) {\r\n data[key] = this.unwrap(data[key]);\r\n }\r\n\r\n return data;\r\n }\r\n\r\n /** @internal */\r\n override _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void {\r\n Object.keys(data).forEach(key => this.unregisterByKey(key));\r\n\r\n const wrappedData: Record<string, WeakValue> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n wrappedData[key] = this.wrapAndRegister(key, value);\r\n }\r\n\r\n this.cacheInternal._setMany<WeakValue>(wrappedData, options);\r\n }\r\n\r\n /** @internal */\r\n override _deleteMany(keys: string[]): void {\r\n keys.forEach(key => this.unregisterByKey(key));\r\n\r\n this.cacheInternal._deleteMany(keys);\r\n }\r\n\r\n override async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const wrappedLoad = async () => this.wrapAndRegister(key, await load());\r\n\r\n return this.unwrap<T>(await this.cache.getOrLoad<WeakValue>(key, wrappedLoad, options))!;\r\n }\r\n\r\n /**\r\n * Wraps the value in a WeakRef and registers it in the FinalizationRegistry if it's an object.\r\n *\r\n * @param key The key to reference the value in the FinalizationRegistry\r\n * @param value The value to wrap\r\n * @returns The wrapped value\r\n */\r\n protected wrapAndRegister(key: string, value: any): WeakValue {\r\n this.unregisterByKey(key);\r\n\r\n if (value !== null && typeof value === 'object') {\r\n this.registry.register(value, key);\r\n\r\n return { v: new WeakRef(value), w: true };\r\n }\r\n\r\n return { v: value, w: false };\r\n }\r\n\r\n /**\r\n * Unwraps the value from a WeakRef if it's an object.\r\n *\r\n * @param data The data to unwrap\r\n * @returns The unwrapped value\r\n */\r\n protected unwrap<T>(data: WeakValue | null): T | null {\r\n if (data === null) {\r\n return null;\r\n }\r\n\r\n if (data.w) {\r\n return data.v.deref() ?? null;\r\n }\r\n\r\n return data.v;\r\n }\r\n\r\n /**\r\n * Unregisters the value from the FinalizationRegistry if it's an object.\r\n *\r\n * @param value The value to unregister\r\n */\r\n protected unregister(value: WeakValue | null): void {\r\n if (value && value.w) {\r\n this.registry.unregister(value.v);\r\n }\r\n }\r\n\r\n /**\r\n * Unregisters the value associated with the given key from the FinalizationRegistry.\r\n *\r\n * @param key The key\r\n */\r\n protected unregisterByKey(key: string): void {\r\n this.unregister(this.cacheInternal._get<WeakValue>(key));\r\n }\r\n}\r\n","import { BaseLocalCache, type LocalCacheInternal } from '../../base/local.js';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface DeepCloningCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache. This must be an in-memory cache.\r\n */\r\n cache: BaseLocalCache;\r\n\r\n /**\r\n * The deep clone function to use.\r\n *\r\n * By default, it will try to use `structuredClone()` if available,\r\n * otherwise it will use a JSON.parse/stringify-based implementation.\r\n *\r\n * @param data The data to deep clone\r\n * @returns The cloned data\r\n */\r\n deepClone?: <T>(data: T) => T;\r\n}\r\n\r\n/**\r\n * A cache layer that deep clones data when reading and writing.\r\n *\r\n * This is useful when you mutate the objects retrieved from cache,\r\n * and you don't want them to also change in cache.\r\n *\r\n * Do not use this layer if you do not intend to mutate cached objects,\r\n * as the cloning process adds unnecessary overhead.\r\n */\r\nexport class DeepCloningCache extends BaseLocalCache {\r\n protected readonly cache: BaseLocalCache;\r\n protected readonly cacheInternal: LocalCacheInternal;\r\n protected deepClone: <T>(data: T) => T;\r\n\r\n constructor(options: DeepCloningCacheOptions) {\r\n super(options);\r\n\r\n this.cache = options.cache;\r\n this.cacheInternal = options.cache.internal;\r\n\r\n if (options.deepClone) {\r\n this.deepClone = options.deepClone;\r\n } else if (typeof structuredClone === 'function') {\r\n // Use structuredClone whenever available since it is faster than JSON\r\n this.deepClone = structuredClone;\r\n } else {\r\n // Since we already expect cached items to be JSON-serializable,\r\n // we can use this simple implementation (that is also pretty fast).\r\n this.deepClone = <T>(data: T): T => JSON.parse(JSON.stringify(data));\r\n }\r\n }\r\n\r\n protected _get<T>(key: string): T | null {\r\n return this.deepClone(this.cacheInternal._get(key));\r\n }\r\n\r\n protected _set<T>(key: string, value: T, options?: SetCacheOptions): void {\r\n this.cacheInternal._set(key, this.deepClone(value), options);\r\n }\r\n\r\n protected _delete(key: string): void {\r\n this.cacheInternal._delete(key);\r\n }\r\n\r\n protected override _getMany<T>(keys: string[]): Record<string, T | null> {\r\n return this.deepClone(this.cacheInternal._getMany<T>(keys));\r\n }\r\n\r\n protected override _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void {\r\n this.cacheInternal._setMany(this.deepClone(data), options);\r\n }\r\n\r\n protected override _deleteMany(keys: string[]): void {\r\n this.cacheInternal._deleteMany(keys);\r\n }\r\n\r\n protected override _addDisposeListener(listener: any): void {\r\n this.cacheInternal._addDisposeListener(listener);\r\n }\r\n\r\n override async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const loadWrapped = async () => this.deepClone(await load());\r\n\r\n return this.deepClone(await this.cache.getOrLoad(key, loadWrapped, options));\r\n }\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\n/**\r\n * A cache implementation that does nothing.\r\n * It's useful for disabling cache and unit testing.\r\n *\r\n * @example\r\n * ```ts\r\n * const cache = isCacheEnabled ? new LocalTTLCache() : new NoOpCache();\r\n * ```\r\n */\r\nexport class NoOpCache implements ICache {\r\n constructor() {}\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n return null;\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return {};\r\n }\r\n\r\n getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n return load();\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {}\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {}\r\n\r\n async delete(key: string): Promise<void> {}\r\n async deleteMany(keys: string[]): Promise<void> {}\r\n\r\n}\r\n","import type { Redis } from 'ioredis';\r\nimport type { Redis as Valkey } from 'iovalkey';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface IORedisCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The ioredis or iovalkey client\r\n */\r\n client: Redis | Valkey;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the UNLINK command.\r\n *\r\n * {@link IORedisCache#delete} and {@link IORedisCache#deleteMany} will use UNLINK instead of DEL if this\r\n * option is set to `true`. This is recommended to improve the deletion performance.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 4.0.0 or above.\r\n *\r\n * @defaultValue true\r\n */\r\n isUNLINKSupported?: boolean;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the MSETEX command.\r\n *\r\n * {@link IORedisCache#setMany} will use MSETEX if this option is set to `true`.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 8.4.0 or above.\r\n * Valkey does not support this yet. (see https://github.com/valkey-io/valkey/issues/2592)\r\n *\r\n * @defaultValue false\r\n */\r\n isMSETEXSupported?: boolean;\r\n}\r\n\r\n/**\r\n * A Redis cache implementation using ioredis\r\n */\r\nexport class IORedisCache extends BaseCache {\r\n protected readonly client: Redis | Valkey;\r\n protected defaultTTL?: number;\r\n protected isUNLINKSupported: boolean;\r\n protected isMSETEXSupported: boolean;\r\n\r\n constructor(options: IORedisCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n this.isUNLINKSupported = options.isUNLINKSupported ?? true;\r\n this.isMSETEXSupported = options.isMSETEXSupported ?? false;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"GET\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"SET\" command...', 'key =', key);\r\n\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n const raw = JSON.stringify(value);\r\n\r\n if (ttl) {\r\n await this.client.set(key, raw, 'EX', ttl);\r\n } else {\r\n await this.client.set(key, raw);\r\n }\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[delete] Running \"UNLINK\" command...', 'key =', key);\r\n\r\n await this.client.unlink(key);\r\n } else {\r\n this.logger?.debug(this.name, '[delete] Running \"DEL\" command...', 'key =', key);\r\n\r\n await this.client.del(key);\r\n }\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"MGET\" command...', 'keys =', keys);\r\n\r\n const values = await this.client.mget(keys);\r\n\r\n const data: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n const value = values[i];\r\n\r\n data[keys[i]!] = value ? JSON.parse(value) : null;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n override async setMany(data: Record<string, any>, options?: SetCacheOptions): Promise<void> {\r\n if (!this.isMSETEXSupported) {\r\n return super.setMany(data, options);\r\n }\r\n\r\n this.logger?.debug(this.name, '[setMany] Running \"MSETEX\" command...', 'data =', data);\r\n\r\n const entries = Object.entries(data);\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n const raw = entries.flatMap(([key, value]) => [\r\n key,\r\n JSON.stringify(value),\r\n ]);\r\n\r\n await this.client.call('MSETEX', entries.length, ...raw, ...(ttl ? ['EX', ttl] : []));\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"UNLINK\" command...', 'keys =', keys);\r\n\r\n await this.client.unlink(keys);\r\n } else {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"DEL\" command...', 'keys =', keys);\r\n\r\n await this.client.del(keys);\r\n }\r\n }\r\n\r\n}\r\n","import type { RedisClientType, RedisClientPoolType, RedisClusterType, RedisSentinelType } from '@redis/client';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\ntype Redis = RedisClientType | RedisClientPoolType | RedisClusterType | RedisSentinelType;\r\n\r\nexport interface RedisCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The Redis client\r\n */\r\n client: RedisClientType | RedisClientPoolType | RedisClusterType | RedisSentinelType;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the UNLINK command.\r\n *\r\n * {@link RedisCache#delete} and {@link RedisCache#deleteMany} will use UNLINK instead of DEL if this\r\n * option is set to `true`. This is recommended to improve the deletion performance.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 4.0.0 or above.\r\n *\r\n * @defaultValue true\r\n */\r\n isUNLINKSupported?: boolean;\r\n\r\n /**\r\n * Indicates whether the Redis server supports the MSETEX command.\r\n *\r\n * {@link RedisCache#setMany} will use MSETEX if this option is set to `true`.\r\n * This is recommended to improve the performance of setting multiple items.\r\n *\r\n * This option should be set to `true` if the server runs Redis OSS 8.4.0 or above.\r\n * Valkey does not support this yet. (see https://github.com/valkey-io/valkey/issues/2592)\r\n *\r\n * @defaultValue false\r\n */\r\n isMSETEXSupported?: boolean;\r\n}\r\n\r\n/**\r\n * A Redis cache implementation using node-redis\r\n */\r\nexport class RedisCache extends BaseCache {\r\n protected readonly client: Redis;\r\n protected defaultTTL?: number;\r\n protected isUNLINKSupported: boolean;\r\n protected isMSETEXSupported: boolean;\r\n\r\n constructor(options: RedisCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n this.isUNLINKSupported = options.isUNLINKSupported ?? true;\r\n this.isMSETEXSupported = options.isMSETEXSupported ?? false;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"GET\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"SET\" command...', 'key =', key);\r\n\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n { expiration: ttl ? { type: 'EX', value: ttl } : undefined },\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[delete] Running \"UNLINK\" command...', 'key =', key);\r\n\r\n await this.client.unlink(key);\r\n } else {\r\n this.logger?.debug(this.name, '[delete] Running \"DEL\" command...', 'key =', key);\r\n\r\n await this.client.del(key);\r\n }\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"MGET\" command...', 'keys =', keys);\r\n\r\n const values = await this.client.mGet(keys);\r\n\r\n const data: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n const value = values[i];\r\n\r\n data[keys[i]!] = value ? JSON.parse(value) : null;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n override async setMany(data: Record<string, any>, options?: SetCacheOptions): Promise<void> {\r\n if (!this.isMSETEXSupported) {\r\n return super.setMany(data, options);\r\n }\r\n\r\n this.logger?.debug(this.name, '[setMany] Running \"MSETEX\" command...', 'data =', data);\r\n\r\n const raw: [string, string][] = [];\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n raw.push([key, JSON.stringify(value)]);\r\n }\r\n\r\n await this.client.mSetEx(\r\n raw,\r\n { expiration: ttl ? { type: 'EX', value: ttl } : undefined },\r\n );\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n if (this.isUNLINKSupported) {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"UNLINK\" command...', 'keys =', keys);\r\n\r\n await this.client.unlink(keys);\r\n } else {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"DEL\" command...', 'keys =', keys);\r\n\r\n await this.client.del(keys);\r\n }\r\n }\r\n\r\n}\r\n","import { BaseCache } from '../../base/index.js';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport type { BaseClient, GlideClient, GlideClusterClient } from '@valkey/valkey-glide';\r\n\r\nexport interface ValkeyGlideCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The GLIDE client instance\r\n */\r\n client: GlideClient | GlideClusterClient | BaseClient;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n}\r\n\r\n/**\r\n * A Valkey cache implementation using @valkey/valkey-glide\r\n */\r\nexport class ValkeyGlideCache extends BaseCache {\r\n protected readonly client: BaseClient;\r\n protected defaultTTL?: number;\r\n\r\n constructor(options: ValkeyGlideCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"GET\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw.toString()) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"SET\" command...', 'key =', key);\r\n\r\n const ttl = options?.ttl ?? this.defaultTTL;\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n { expiry: ttl ? { type: 'EX' as any, count: ttl } : undefined },\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Running \"UNLINK\" command...', 'key =', key);\r\n\r\n await this.client.unlink([key]);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"MGET\" command...', 'keys =', keys);\r\n\r\n const values = await this.client.mget(keys);\r\n\r\n const data: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n const value = values[i];\r\n\r\n data[keys[i]!] = value ? JSON.parse(value.toString()) : null;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany] Running \"UNLINK\" command...', 'keys =', keys);\r\n\r\n await this.client.unlink(keys);\r\n }\r\n\r\n}\r\n","import type Memcache from 'memcache';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface MemcacheCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The Memcache client\r\n */\r\n client: Memcache;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n}\r\n\r\n/**\r\n * A Memcached cache implementation using Memcache\r\n */\r\nexport class MemcacheCache extends BaseCache {\r\n protected readonly client: Memcache;\r\n protected defaultTTL?: number;\r\n\r\n constructor(options: MemcacheCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"get\" command...', 'key =', key);\r\n\r\n const raw = await this.client.get(key);\r\n\r\n return raw ? JSON.parse(raw) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"set\" command...', 'key =', key);\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n options?.ttl ?? this.defaultTTL,\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Running \"delete\" command...', 'key =', key);\r\n\r\n await this.client.delete(key);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany] Running \"get\" command...', 'keys =', keys);\r\n\r\n const raw = await this.client.gets(keys);\r\n const data: Record<string, T | null> = {};\r\n\r\n raw.forEach((value, key) => {\r\n data[key] = value ? JSON.parse(value) : null;\r\n });\r\n\r\n return data;\r\n }\r\n}\r\n","import type { Client } from 'memjs';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface MemJSCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The memjs client\r\n */\r\n client: Client;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL?: number;\r\n}\r\n\r\n/**\r\n * A Memcached cache implementation using MemJS\r\n */\r\nexport class MemJSCache extends BaseCache {\r\n protected readonly client: Client;\r\n protected defaultTTL?: number;\r\n\r\n constructor(options: MemJSCacheOptions) {\r\n super(options);\r\n this.client = options.client;\r\n this.defaultTTL = options.defaultTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get] Running \"get\" command...', 'key =', key);\r\n\r\n const { value } = await this.client.get(key);\r\n\r\n return value ? JSON.parse(value.toString('utf8')) : null;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Running \"set\" command...', 'key =', key);\r\n\r\n await this.client.set(\r\n key,\r\n JSON.stringify(value),\r\n {\r\n expires: options?.ttl ?? this.defaultTTL,\r\n },\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Running \"delete\" command...', 'key =', key);\r\n\r\n await this.client.delete(key);\r\n }\r\n\r\n}\r\n","import type { KVNamespace } from '@cloudflare/workers-types';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport { BaseCache } from '../../base/index.js';\r\n\r\nexport interface WorkersKVCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The KV namespace (`env.NAMESPACE`)\r\n */\r\n kv: KVNamespace;\r\n\r\n /**\r\n * The amount of time in seconds that a KV result is cached in the global network location it is accessed from.\r\n *\r\n * Increasing this value can improve read performance at the cost of data being stale.\r\n *\r\n * @see https://developers.cloudflare.com/kv/api/read-key-value-pairs/#cachettl-parameter\r\n */\r\n edgeCacheTTL?: number;\r\n}\r\n\r\n/**\r\n * A Cloudflare Workers KV cache implementation.\r\n */\r\nexport class WorkersKVCache extends BaseCache {\r\n protected readonly kv: KVNamespace;\r\n protected edgeCacheTTL?: number;\r\n\r\n constructor(options: WorkersKVCacheOptions) {\r\n super(options);\r\n this.kv = options.kv;\r\n this.edgeCacheTTL = options.edgeCacheTTL;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.kv.get<T>(key, { type: 'json', cacheTtl: this.edgeCacheTTL });\r\n }\r\n\r\n set<T>(key: string, value: T, options: SetCacheOptions = {}): Promise<void> {\r\n return this.kv.put(key, JSON.stringify(value), { expirationTtl: options.ttl });\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.kv.delete(key);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const data = await this.kv.get<T>(keys, { type: 'json', cacheTtl: this.edgeCacheTTL });\r\n\r\n return Object.fromEntries(data);\r\n }\r\n\r\n}\r\n","import type { IMap } from 'hazelcast-client';\r\nimport { BaseCache } from '../../base/index.js';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface HazelcastCacheOptions extends BaseCacheOptions {\r\n /**\r\n * Hazelcast map instance.\r\n *\r\n * Obtain it through a Hazelcast client:\r\n *\r\n * ```ts\r\n * import { Client } from 'hazelcast-client';\r\n *\r\n * const client = await Client.newHazelcastClient();\r\n * const map = await client.getMap('my-cache');\r\n *\r\n * const cache = new HazelcastCache({ map });\r\n * ```\r\n */\r\n map: IMap<string, any>;\r\n}\r\n\r\n/**\r\n * A Hazelcast cache implementation using an IMap\r\n */\r\nexport class HazelcastCache extends BaseCache {\r\n protected readonly map: IMap<string, any>;\r\n\r\n constructor(options: HazelcastCacheOptions) {\r\n super(options);\r\n this.map = options.map;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.map.get(key);\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return this.map.set(key, value, options?.ttl);\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.map.delete(key);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const entries = await this.map.getAll(keys);\r\n const data: Record<string, T | null> = {};\r\n\r\n for (const [key, value] of entries) {\r\n data[key] = value;\r\n }\r\n\r\n return data;\r\n }\r\n}\r\n","import { BaseCache } from '../../base/index.js';\r\nimport type { BaseCacheOptions, SetCacheOptions } from '../../types/cache.js';\r\nimport type Keyv from 'keyv';\r\n\r\nexport interface KeyvCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying key-value store\r\n */\r\n keyv: Keyv;\r\n}\r\n\r\nexport class KeyvCache extends BaseCache {\r\n protected readonly keyv: Keyv;\r\n\r\n constructor(options: KeyvCacheOptions) {\r\n super(options);\r\n this.keyv = options.keyv;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const result = await this.keyv.get<T>(key);\r\n\r\n return result === undefined ? null : result;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n await this.keyv.set(key, value, options?.ttl);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n await this.keyv.delete(key);\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const data = await this.keyv.getMany(keys);\r\n const result: Record<string, T | null> = {};\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n result[keys[i]] = data[i] === undefined ? null : data[i];\r\n }\r\n\r\n return result;\r\n }\r\n\r\n override async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n const ttl = options?.ttl;\r\n\r\n await this.keyv.setMany(\r\n Object.entries(data).map(([key, value]) => ({\r\n key,\r\n value,\r\n ttl,\r\n })),\r\n );\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n await this.keyv.deleteMany(keys);\r\n }\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface AsyncLazyCacheOptions {\r\n /**\r\n * A factory function that will be called to create the underlying cache when needed.\r\n */\r\n factory: () => Promise<ICache> | ICache;\r\n\r\n /**\r\n * Whether it should initialize only when needed.\r\n *\r\n * - When set to `true`, it will initialize the cache only when a method is called.\r\n * - When set to `false`, it will initialize the cache upon construction.\r\n *\r\n * @default `false`\r\n */\r\n lazy?: boolean;\r\n}\r\n\r\n/**\r\n * A cache layer that initializes the underlying cache asynchronously.\r\n *\r\n * This layer can be used to connect to an external cache with the cache methods already available.\r\n *\r\n * This layer can also be used to lazily initialize the cache only when it's actually needed.\r\n *\r\n * @example\r\n * ```ts\r\n * const cache = new AsyncCache({\r\n * factory: async () => {\r\n * const redisClient = await createClient({\r\n * url: \"redis://user:password@localhost:6380\",\r\n * });\r\n *\r\n * return new RedisCache({ client: redisClient });\r\n * },\r\n * lazy: true,\r\n * });\r\n *\r\n * cache.get(\"key\")\r\n * .then(result => console.log('redis was connected and read the key:', value));\r\n * ```\r\n */\r\nexport class AsyncLazyCache implements ICache {\r\n protected readonly factory: () => Promise<ICache> | ICache;\r\n protected cache: Promise<ICache> | null = null;\r\n\r\n constructor(options: AsyncLazyCacheOptions) {\r\n this.factory = options.factory;\r\n\r\n if (!options.lazy) {\r\n this.cache = Promise.resolve(this.factory());\r\n }\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n return (await this.resolveCache()).get<T>(key);\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n return (await this.resolveCache()).getOrLoad<T>(key, load, options);\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return (await this.resolveCache()).set<T>(key, value, options);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n return (await this.resolveCache()).delete(key);\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return (await this.resolveCache()).getMany<T>(keys);\r\n }\r\n\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n return (await this.resolveCache()).setMany<T>(data, options);\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n return (await this.resolveCache()).deleteMany(keys);\r\n }\r\n\r\n /**\r\n * Gets the underlying cache, initializing it if not already initialized.\r\n */\r\n public resolveCache(): Promise<ICache> {\r\n if (!this.cache) {\r\n this.cache = Promise.resolve(this.factory());\r\n }\r\n\r\n return this.cache;\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.d.ts';\r\nimport type { Logger } from '../../types/logger.js';\r\n\r\n/**\r\n * The options to construct the {@link CoalescingCache}\r\n */\r\nexport interface CoalescingCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n}\r\n\r\ninterface OngoingRequest {\r\n promise: Promise<any | null>;\r\n type: 'get' | 'getOrLoad';\r\n}\r\n\r\n/**\r\n * A cache strategy layer that deduplicates parallel requests into a single request.\r\n *\r\n * This strategy can prevent the Thundering Herd problem as all parallel requests will be coalesced into one.\r\n */\r\nexport class CoalescingCache implements ICache {\r\n protected readonly ongoingRequests: Map<string, OngoingRequest> = new Map();\r\n protected readonly cache: ICache;\r\n protected readonly name?: string;\r\n protected readonly logger?: Logger;\r\n\r\n constructor(options: CoalescingCacheOptions) {\r\n this.cache = options.cache;\r\n this.name = options.name;\r\n this.logger = options.logger;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n const ongoingRequest = this.ongoingRequests.get(key);\r\n\r\n if (ongoingRequest) {\r\n this.logger?.debug(this.name, '[get] Returning ongoing request...', 'key =', key);\r\n\r\n return ongoingRequest.promise;\r\n }\r\n\r\n this.logger?.debug(this.name, '[get] Reading from underlying cache...', 'key =', key);\r\n\r\n const promise = this.cache.get<T>(key);\r\n\r\n this.ongoingRequests.set(key, { promise, type: 'get' });\r\n\r\n return promise.finally(() => this.ongoingRequests.delete(key));\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const ongoingRequest = this.ongoingRequests.get(key);\r\n\r\n // When there's no ongoing requests, we'll do a new one\r\n if (!ongoingRequest) {\r\n this.logger?.debug(this.name, '[getOrLoad] Reading from the underlying cache...', 'key =', key);\r\n\r\n const promise = this.cache.getOrLoad(key, load, options);\r\n\r\n this.ongoingRequests.set(key, { promise, type: 'getOrLoad' });\r\n\r\n return promise.finally(() => this.ongoingRequests.delete(key));\r\n }\r\n\r\n // We'll await the ongoing request\r\n let request = await ongoingRequest.promise;\r\n\r\n // When the request is successful or the type is already getOrLoad, we'll just return it\r\n if (request !== null || ongoingRequest.type === 'getOrLoad') {\r\n this.logger?.debug(this.name, '[getOrLoad] Read from an ongoing request.', 'key =', key);\r\n\r\n return request;\r\n }\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Refreshing the cache...', 'key =', key);\r\n\r\n // Otherwise, we'll load it manually\r\n const promise = load();\r\n\r\n this.ongoingRequests.set(key, { promise, type: 'getOrLoad' });\r\n\r\n try {\r\n request = await promise;\r\n\r\n // When the request is successful, we'll store it in cache\r\n if (request !== null) {\r\n await this.cache.set(key, request, options);\r\n }\r\n } finally {\r\n // We'll only delete from \"ongoing requests\" when we finish saving it\r\n this.ongoingRequests.delete(key);\r\n }\r\n\r\n return request;\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const promise = this.cache.set<T>(key, value, options);\r\n\r\n this.ongoingRequests.set(key, {\r\n promise: promise.then(() => value),\r\n type: 'getOrLoad',\r\n });\r\n\r\n return promise.finally(() => this.ongoingRequests.delete(key));\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n try {\r\n this.ongoingRequests.set(key, {\r\n type: 'get',\r\n promise: Promise.resolve(null),\r\n });\r\n\r\n await this.cache.delete(key);\r\n } finally {\r\n this.ongoingRequests.delete(key);\r\n }\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const items: [string, Promise<T | null>][] = [];\r\n const remainingKeys: string[] = [];\r\n\r\n for (const key of keys) {\r\n const ongoingRequest = this.ongoingRequests.get(key);\r\n\r\n if (ongoingRequest) {\r\n items.push([key, ongoingRequest.promise]);\r\n } else {\r\n remainingKeys.push(key);\r\n }\r\n }\r\n\r\n this.logger?.debug(this.name, '[getMany]', items.length, 'ongoing requests found, reading', remainingKeys.length, 'resources.', 'keys =', keys);\r\n\r\n if (remainingKeys.length > 0) {\r\n const promise = this.cache.getMany<T>(remainingKeys);\r\n\r\n for (const key of remainingKeys) {\r\n const itemPromise = promise\r\n .then(data => data[key]!)\r\n .finally(() => this.ongoingRequests.delete(key));\r\n\r\n this.ongoingRequests.set(key, {\r\n promise: itemPromise,\r\n type: 'get',\r\n });\r\n\r\n items.push([key, itemPromise]);\r\n }\r\n }\r\n\r\n return Object.fromEntries(\r\n await Promise.all(\r\n items.map(async ([key, promise]) => [key, await promise])\r\n ),\r\n );\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany]', 'data =', data);\r\n\r\n const promise = this.cache.setMany(data, options);\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n this.ongoingRequests.set(key, {\r\n promise: promise.then(() => value).finally(() => this.ongoingRequests.delete(key)),\r\n type: 'getOrLoad',\r\n });\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany]', 'keys =', keys);\r\n\r\n try {\r\n for (const key of keys) {\r\n this.ongoingRequests.set(key, {\r\n type: 'get',\r\n promise: Promise.resolve(null),\r\n });\r\n }\r\n\r\n await this.cache.deleteMany(keys);\r\n } finally {\r\n for (const key of keys) {\r\n this.ongoingRequests.delete(key);\r\n }\r\n }\r\n\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface FailSafeCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n\r\n /**\r\n * The error policy\r\n */\r\n policy?: ErrorPolicy;\r\n\r\n /**\r\n * A callback that is called when an error occurs.\r\n * This is useful for logging or metrics.\r\n *\r\n * @param operation In which operation call the error occurred\r\n * @param error The error that occurred\r\n */\r\n onError?: (operation: ErrorPolicyOperation, error: unknown) => void;\r\n}\r\n\r\ntype ErrorPolicyOperation = 'get' | 'set' | 'delete' | 'getOrLoad';\r\n\r\nexport interface ErrorPolicy {\r\n /**\r\n * Policy for when the {@link ICache#get} and {@link ICache#getMany} throw errors\r\n *\r\n * - 'fail-open': return null on error\r\n * - 'fail-closed': throw on error\r\n *\r\n * @defaultValue 'fail-open'\r\n */\r\n get?: 'fail-open' | 'fail-closed';\r\n\r\n /**\r\n * Policy for when the {@link ICache#set} and {@link ICache#setMany} throws errors\r\n *\r\n * - 'fail-open': does nothing on error\r\n * - 'fail-closed': throw on error\r\n *\r\n * @defaultValue 'fail-open'\r\n */\r\n set?: 'fail-open' | 'fail-closed';\r\n\r\n /**\r\n * Policy for when the {@link ICache#delete} and {@link ICache#deleteMany} throws errors\r\n *\r\n * - 'fail-open': does nothing on error\r\n * - 'fail-closed': throw on error\r\n *\r\n * @defaultValue 'fail-closed'\r\n */\r\n delete?: 'fail-open' | 'fail-closed';\r\n\r\n /**\r\n * Policy for when the {@link ICache#getOrLoad} throws errors.\r\n * This does not include errors from the `load` function, only the cache operations.\r\n *\r\n * - 'fail-open': loads from origin on error\r\n * - 'fail-closed': throw on error\r\n *\r\n * @defaultValue 'fail-open'\r\n */\r\n getOrLoad?: 'fail-open' | 'fail-closed';\r\n}\r\n\r\n/**\r\n * Handles errors from an underlying cache according to a specified policy.\r\n *\r\n * @see https://read.thecoder.cafe/p/fail-open-fail-closed\r\n */\r\nexport class FailSafeCache implements ICache {\r\n protected readonly cache: ICache;\r\n protected readonly policy: ErrorPolicy;\r\n protected readonly onError?: (operation: ErrorPolicyOperation, error: unknown) => void;\r\n\r\n constructor(options: FailSafeCacheOptions) {\r\n this.cache = options.cache;\r\n this.policy = {\r\n get: 'fail-open',\r\n set: 'fail-open',\r\n delete: 'fail-closed',\r\n getOrLoad: 'fail-open',\r\n ...options.policy || {},\r\n };\r\n this.onError = options.onError;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.cache.get<T>(key).catch(error => this.handleError('get', error, null));\r\n }\r\n\r\n getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return this.cache.getMany<T>(keys).catch(error => this.handleError('get', error, {}));\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.set(key, value, options).catch(error => this.handleError('set', error, void 0));\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.setMany(data, options).catch(error => this.handleError('set', error, void 0));\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.cache.delete(key).catch(error => this.handleError('delete', error, void 0));\r\n }\r\n\r\n deleteMany(keys: string[]): Promise<void> {\r\n return this.cache.deleteMany(keys).catch(error => this.handleError('delete', error, void 0));\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n let loadResult: T;\r\n let loadErrored = false;\r\n let loadSuccessful = false;\r\n\r\n const loadWithErrorHandling = async (): Promise<T> => {\r\n try {\r\n loadResult = await load();\r\n loadSuccessful = true;\r\n return loadResult;\r\n } catch (error) {\r\n loadErrored = true;\r\n throw error;\r\n }\r\n };\r\n\r\n try {\r\n return await this.cache.getOrLoad(key, loadWithErrorHandling, options);\r\n } catch (error) {\r\n // We pass through load errors\r\n if (loadErrored) {\r\n throw error;\r\n }\r\n\r\n // We let the errors be handled according to policy\r\n await this.handleError('getOrLoad', error, null);\r\n\r\n // In case handleError didn't throw, we load from origin\r\n return loadSuccessful ? loadResult! : await load();\r\n }\r\n }\r\n\r\n protected handleError<T>(operation: ErrorPolicyOperation, error: unknown, failOpenValue: T): Promise<T> {\r\n this.onError?.(operation, error);\r\n\r\n const policy = this.policy[operation];\r\n\r\n if (policy === 'fail-open') {\r\n return Promise.resolve(failOpenValue);\r\n } else {\r\n return Promise.reject(error);\r\n }\r\n }\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface JitteringCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL: number;\r\n\r\n /**\r\n * The maximum jitter (in seconds) to add to the TTL of cached items.\r\n */\r\n maxJitterTTL: number;\r\n}\r\n\r\n/**\r\n * A cache layer that adds a random jitter to the TTL of cached items to prevent cache stampedes.\r\n *\r\n * This layer is useful in scenarios where many cached items expire simultaneously, causing a sudden surge of requests to the underlying data source.\r\n */\r\nexport class JitteringCache implements ICache {\r\n protected readonly cache: ICache;\r\n protected defaultTTL: number;\r\n protected maxJitterTTL: number;\r\n\r\n constructor(options: JitteringCacheOptions) {\r\n this.cache = options.cache;\r\n this.defaultTTL = options.defaultTTL;\r\n this.maxJitterTTL = options.maxJitterTTL;\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.cache.get<T>(key);\r\n }\r\n\r\n getOrLoad<T>(key: string, load: () => Promise<T>, options: SetCacheOptions = {}): Promise<T> {\r\n return this.cache.getOrLoad<T>(key, load, this.jitterTTL(options));\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.set<T>(key, value, this.jitterTTL(options));\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.cache.delete(key);\r\n }\r\n\r\n getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n return this.cache.getMany(keys);\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.setMany(data, this.jitterTTL(options));\r\n }\r\n\r\n deleteMany(keys: string[]): Promise<void> {\r\n return this.cache.deleteMany(keys);\r\n }\r\n\r\n protected jitterTTL(options: SetCacheOptions = {}): SetCacheOptions {\r\n const ttl = options.ttl ?? this.defaultTTL;\r\n const jitter = Math.random() * this.maxJitterTTL;\r\n\r\n return {\r\n ...options,\r\n ttl: ttl + jitter,\r\n };\r\n }\r\n}\r\n","import type { ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\ninterface BaseKeyTransformingCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n}\r\n\r\ninterface KeyTransformerFnCacheOptions extends BaseKeyTransformingCacheOptions {\r\n /**\r\n * The function that will be called with each key to transform it.\r\n * @param key The original key\r\n * @return The transformed key\r\n */\r\n transform: (key: string) => string;\r\n prefix?: never;\r\n suffix?: never;\r\n}\r\n\r\ninterface KeyAffixCacheOptions extends BaseKeyTransformingCacheOptions {\r\n /**\r\n * The prefix to add to keys\r\n */\r\n prefix?: string;\r\n\r\n /**\r\n * The suffix to add to keys\r\n */\r\n suffix?: string;\r\n}\r\n\r\nexport type KeyTransformingCacheOptions = KeyAffixCacheOptions | KeyTransformerFnCacheOptions;\r\n\r\n/**\r\n * A cache layer that changes keys before passing them to the underlying cache.\r\n *\r\n * This layer can be used to:\r\n * - Create namespaced caches, avoiding conflicts with shared cache servers.\r\n * - Add a version number, allowing schema changes without causing incompatibility.\r\n * - Implement any other key transformations, such as normalizing or hashing.\r\n */\r\nexport class KeyTransformingCache implements ICache {\r\n protected readonly cache: ICache;\r\n protected transform: (key: string) => string;\r\n\r\n constructor(options: KeyTransformingCacheOptions) {\r\n this.cache = options.cache;\r\n\r\n if ('transform' in options && typeof options.transform === 'function') {\r\n this.transform = options.transform;\r\n } else {\r\n const prefix = options.prefix || '';\r\n const suffix = options.suffix || '';\r\n this.transform = (key: string) => `${prefix}${key}${suffix}`;\r\n }\r\n }\r\n\r\n get<T>(key: string): Promise<T | null> {\r\n return this.cache.get<T>(this.transform(key));\r\n }\r\n\r\n getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n return this.cache.getOrLoad(this.transform(key), load, options);\r\n }\r\n\r\n set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.set(this.transform(key), value, options);\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n return this.cache.delete(this.transform(key));\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const transformedKeys = keys.map(key => this.transform(key));\r\n const data = await this.cache.getMany<T>(transformedKeys);\r\n\r\n return Object.fromEntries(\r\n Object.entries(data).map(([transformedKey, value]) => [\r\n keys[transformedKeys.indexOf(transformedKey)],\r\n value,\r\n ]),\r\n );\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n return this.cache.setMany(\r\n Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [this.transform(key), value]),\r\n ),\r\n options,\r\n )\r\n }\r\n\r\n deleteMany(keys: string[]): Promise<void> {\r\n return this.cache.deleteMany(keys.map(key => this.transform(key)));\r\n }\r\n}\r\n","import type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.js';\r\nimport type { Logger } from '../../types/logger.js';\r\n\r\n/**\r\n * The options to create the {@link SWRCache}\r\n */\r\nexport interface SWRCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n\r\n /**\r\n * The default Time To Live in seconds\r\n */\r\n defaultTTL: number;\r\n\r\n /**\r\n * The additional time in seconds to keep the resource stored, but consider it as stale\r\n */\r\n staleTTL: number;\r\n}\r\n\r\ninterface CachedItem<T> {\r\n data: T;\r\n expiresAt: number;\r\n}\r\n\r\n/**\r\n * A cache strategy that returns stale resources immediately while it refreshes the cache in background.\r\n *\r\n * This is an implementation of the Stale-While-Revalidate algorithm.\r\n *\r\n * This strategy is only effective when calling {@link ICache#getOrLoad}.\r\n */\r\nexport class SWRCache implements ICache {\r\n protected readonly revalidating: Map<string, Promise<any>> = new Map<string, Promise<any>>();\r\n protected readonly cache: ICache;\r\n protected readonly name?: string;\r\n protected readonly logger?: Logger;\r\n protected defaultTTL: number;\r\n protected staleTTL: number;\r\n\r\n constructor(options: SWRCacheOptions) {\r\n this.cache = options.cache;\r\n this.name = options.name;\r\n this.logger = options.logger;\r\n this.defaultTTL = options.defaultTTL;\r\n this.staleTTL = options.staleTTL;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n this.logger?.debug(this.name, '[get]', 'key =', key);\r\n\r\n const item = await this.cache.get<CachedItem<T>>(key);\r\n\r\n return item ? item.data : null;\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options: SetCacheOptions = {}): Promise<T> {\r\n this.logger?.debug(this.name, '[getOrLoad]', 'key =', key);\r\n\r\n const ttl = options.ttl || this.defaultTTL;\r\n const cacheOptions = {\r\n ...options,\r\n ttl: ttl + this.staleTTL,\r\n };\r\n\r\n const loadItem = async (): Promise<CachedItem<T>> => ({\r\n data: await load(),\r\n expiresAt: Date.now() + ttl * 1000,\r\n });\r\n\r\n const item = await this.cache.getOrLoad<CachedItem<T>>(key, loadItem, cacheOptions);\r\n\r\n // The item is stale, we'll revalidate in background\r\n if (item && item.expiresAt < Date.now() && !this.revalidating.has(key)) {\r\n this.logger?.debug(this.name, '[getOrLoad] Refreshing stale resource in background...', 'key =', key);\r\n\r\n const promise = loadItem()\r\n .then(newItem => this.cache.set(key, newItem, cacheOptions))\r\n .finally(() => this.revalidating.delete(key));\r\n\r\n this.revalidating.set(key, promise);\r\n }\r\n\r\n return item.data;\r\n }\r\n\r\n set<T>(key: string, value: T, options: SetCacheOptions = {}): Promise<void> {\r\n this.logger?.debug(this.name, '[set]', 'key =', key);\r\n\r\n const ttl = options.ttl || this.defaultTTL;\r\n const item: CachedItem<T> = {\r\n data: value,\r\n expiresAt: Date.now() + ttl * 1000,\r\n };\r\n const cacheOptions = {\r\n ...options,\r\n ttl: ttl + this.staleTTL,\r\n };\r\n\r\n return this.cache.set(key, item, cacheOptions);\r\n }\r\n\r\n delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete]', 'key =', key);\r\n\r\n return this.cache.delete(key);\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n this.logger?.debug(this.name, '[getMany]', 'keys =', keys);\r\n\r\n const data = await this.cache.getMany<CachedItem<T>>(keys);\r\n const items: Record<string, T | null> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n items[key] = value ? value.data : null;\r\n }\r\n\r\n return items;\r\n }\r\n\r\n setMany<T>(data: Record<string, T>, options: SetCacheOptions = {}): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany]', 'data =', data);\r\n\r\n const ttl = options.ttl || this.defaultTTL;\r\n const items: Record<string, CachedItem<T>> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n items[key] = {\r\n data: value,\r\n expiresAt: Date.now() + ttl * 1000,\r\n };\r\n }\r\n\r\n return this.cache.setMany(items, {\r\n ...options,\r\n ttl: ttl + this.staleTTL,\r\n });\r\n }\r\n\r\n deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany]', 'keys =', keys);\r\n\r\n return this.cache.deleteMany(keys);\r\n }\r\n\r\n}\r\n","import { BaseCache } from '../../base/index.js';\r\nimport type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.js';\r\n\r\nexport interface TieredCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The list of tiers in order of priority.\r\n *\r\n * The first item represents the \"hot\" cache while the last one represents a \"cold\" cache.\r\n */\r\n tiers: CacheTier[];\r\n}\r\n\r\nexport interface CacheTier {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n\r\n /**\r\n * The options that will be passed to {@link ICache#getOrLoad}, {@link ICache#set} and {@link ICache#setMany}.\r\n */\r\n options?: SetCacheOptions;\r\n}\r\n\r\n/**\r\n * A cache strategy layer that implements multi-level caching\r\n *\r\n * The objective of a tiered cache is to minimize latency while still having the benefits of a larger, shared cache.\r\n * This is done by having the first tier being an in-memory cache (such as {@link LocalTTLCache}) that stores a small amount of items with a short TTL,\r\n * and the second tier being an external cache (such as {@link RedisCache}) that stores a lot more items and may have a longer TTL.\r\n *\r\n * This strategy is similarly known as Cache Hierarchy, CPU cache or L1/L2/L3 cache.\r\n */\r\nexport class TieredCache extends BaseCache {\r\n protected readonly tiers: CacheTier[];\r\n\r\n constructor(options: TieredCacheOptions) {\r\n super(options);\r\n this.tiers = options.tiers;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const next = (i: number): Promise<T | null> => {\r\n this.logger?.debug(this.name, '[get] Reading from tier =', i, 'key =', key);\r\n\r\n const tier = this.tiers[i]!;\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n if (isLastTier) {\r\n return tier.cache.get<T>(key);\r\n }\r\n\r\n return tier.cache.getOrLoad(key, () => next(i + 1), tier.options);\r\n };\r\n\r\n return next(0);\r\n }\r\n\r\n override async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n const next = (i: number): Promise<T> => {\r\n this.logger?.debug(this.name, '[getOrLoad] Reading from tier =', i, 'key =', key);\r\n\r\n const tier = this.tiers[i]!;\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n if (isLastTier) {\r\n return tier.cache.getOrLoad(key, load, options || tier.options);\r\n }\r\n\r\n return tier.cache.getOrLoad(key, () => next(i + 1), tier.options);\r\n };\r\n\r\n return next(0);\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[set] Writing to all tiers in parallel...', 'key =', key);\r\n\r\n await Promise.all(\r\n this.tiers.map((tier, i) => {\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n return tier.cache.set(key, value, isLastTier ? (options || tier.options) : tier.options);\r\n }),\r\n );\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.logger?.debug(this.name, '[delete] Deleting from all tiers in parallel...', 'key =', key);\r\n\r\n await Promise.all(\r\n this.tiers.map(tier => tier.cache.delete(key)),\r\n );\r\n }\r\n\r\n override async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const next = async (i: number, remainingKeys: string[]): Promise<Record<string, T | null>> => {\r\n this.logger?.debug(this.name, '[getMany] Reading from tier =', i, 'keys =', keys);\r\n\r\n const tier = this.tiers[i]!;\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n const items = await tier.cache.getMany<T>(remainingKeys);\r\n\r\n remainingKeys = Object.entries(items)\r\n .filter(([, value]) => value === null || value === undefined)\r\n .map(([key]) => key);\r\n\r\n if (isLastTier || remainingKeys.length === 0) {\r\n return items;\r\n }\r\n\r\n const nextItems = await next(i + 1, remainingKeys);\r\n\r\n const backfillItems = Object.entries(nextItems)\r\n .filter(([, value]) => value !== null && value !== undefined);\r\n\r\n if (backfillItems.length > 0) {\r\n await tier.cache.setMany(Object.fromEntries(backfillItems), tier.options);\r\n }\r\n\r\n return {\r\n ...items,\r\n ...nextItems,\r\n };\r\n };\r\n\r\n return next(0, keys);\r\n }\r\n\r\n override async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n this.logger?.debug(this.name, '[setMany] Writing to all tiers in parallel...', 'data =', data);\r\n\r\n await Promise.all(\r\n this.tiers.map((tier, i) => {\r\n const isLastTier = i === this.tiers.length - 1;\r\n\r\n return tier.cache.setMany(data, isLastTier ? (options || tier.options) : tier.options);\r\n }),\r\n );\r\n }\r\n\r\n override async deleteMany(keys: string[]): Promise<void> {\r\n this.logger?.debug(this.name, '[deleteMany] Deleting from all tiers in parallel...', 'keys =', keys);\r\n\r\n await Promise.all(\r\n this.tiers.map(tier => tier.cache.deleteMany(keys)),\r\n );\r\n }\r\n\r\n}\r\n","import type { BaseCacheOptions, ICache, SetCacheOptions } from '../../types/cache.js';\r\nimport type { Logger } from '../../types/logger.js';\r\n\r\nexport interface MetricsCollectingCacheOptions extends BaseCacheOptions {\r\n /**\r\n * The underlying cache\r\n */\r\n cache: ICache;\r\n}\r\n\r\ninterface CacheCountMetrics {\r\n /** Amount of times the cache didn't have the requested resource */\r\n missCount: number;\r\n\r\n /** The amount of times the cache returned the requested resource */\r\n hitCount: number;\r\n\r\n /** The amount of times the cache was refreshed (the `load` function was called in {@link ICache#getOrLoad}) */\r\n loadCount: number;\r\n\r\n /** The amount of times the cache was updated */\r\n setCount: number;\r\n\r\n /** The amount of times a cached resource was invalidated */\r\n deleteCount: number;\r\n}\r\n\r\ninterface CacheTimeMetrics {\r\n /** Average time taken to verify that the cache didn't have a single requested resource (in milliseconds) */\r\n missTime: number;\r\n\r\n /** Average time taken to return a single requested resource from cache (in milliseconds) */\r\n hitTime: number;\r\n\r\n /** Average time taken to load a single resource from source (in milliseconds) */\r\n loadTime: number;\r\n\r\n /** Average time taken to update a single resource from cache (in milliseconds) */\r\n setTime: number;\r\n\r\n /** Average time taken to invalidate a single resource from cache (in milliseconds) */\r\n deleteTime: number;\r\n}\r\n\r\nexport type CacheMetrics = CacheCountMetrics & CacheTimeMetrics;\r\n\r\n/**\r\n * A cache layer that collects metrics from each cache call.\r\n *\r\n * This can be useful to measure the cache effectiveness\r\n */\r\nexport class MetricsCollectingCache implements ICache {\r\n protected readonly cache: ICache;\r\n protected readonly logger?: Logger;\r\n protected name?: string;\r\n\r\n protected countMetrics: CacheCountMetrics = {\r\n missCount: 0,\r\n hitCount: 0,\r\n loadCount: 0,\r\n setCount: 0,\r\n deleteCount: 0,\r\n };\r\n protected totalTimeMetrics: CacheTimeMetrics = {\r\n missTime: 0,\r\n hitTime: 0,\r\n loadTime: 0,\r\n setTime: 0,\r\n deleteTime: 0,\r\n };\r\n\r\n constructor(options: MetricsCollectingCacheOptions) {\r\n this.cache = options.cache;\r\n this.logger = options.logger;\r\n this.name = options.name;\r\n }\r\n\r\n async get<T>(key: string): Promise<T | null> {\r\n const startAt = performance.now();\r\n\r\n const data = await this.cache.get<T>(key);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n if (data === null) {\r\n this.countMetrics.missCount++;\r\n this.totalTimeMetrics.missTime += time;\r\n\r\n this.logger?.debug(this.name, '[get] Cache miss.', 'key =', key, 'timeMS =', time);\r\n } else {\r\n this.countMetrics.hitCount++;\r\n this.totalTimeMetrics.hitTime += time;\r\n\r\n this.logger?.debug(this.name, '[get] Cache hit.', 'key =', key, 'timeMS =', time);\r\n }\r\n\r\n return data;\r\n }\r\n\r\n async getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T> {\r\n let didTriggerLoad: boolean = false;\r\n let loadFinishAt: number = 0;\r\n\r\n const loadMiddleware = (): Promise<T> => {\r\n const missFinishAt = performance.now();\r\n\r\n this.countMetrics.missCount++;\r\n this.totalTimeMetrics.missTime += missFinishAt - startAt;\r\n\r\n didTriggerLoad = true;\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Cache refresh.', 'key =', key);\r\n\r\n const loadStartAt = performance.now();\r\n\r\n return load().finally(() => {\r\n loadFinishAt = performance.now();\r\n\r\n this.countMetrics.loadCount++;\r\n this.totalTimeMetrics.loadTime += loadFinishAt - loadStartAt;\r\n });\r\n };\r\n\r\n let startAt = performance.now();\r\n\r\n const data = await this.cache.getOrLoad<T>(key, loadMiddleware, options);\r\n\r\n if (!didTriggerLoad) {\r\n const hitFinishedAt = performance.now();\r\n\r\n this.countMetrics.hitCount++;\r\n this.totalTimeMetrics.hitTime += hitFinishedAt - startAt;\r\n\r\n this.logger?.debug(this.name, '[getOrLoad] Cache hit.', 'key =', key);\r\n } else {\r\n const setFinishAt = performance.now();\r\n\r\n this.countMetrics.setCount++;\r\n this.totalTimeMetrics.setTime += setFinishAt - loadFinishAt;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n async set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.set(key, value, options);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n this.countMetrics.setCount++;\r\n this.totalTimeMetrics.setTime += time;\r\n\r\n this.logger?.debug(this.name, '[set] Cache set.', 'key =', key, 'timeMS =', time);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.delete(key);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n this.countMetrics.deleteCount++;\r\n this.totalTimeMetrics.deleteTime += time;\r\n\r\n this.logger?.debug(this.name, '[delete] Cache delete.', 'key =', key, 'timeMS =', time);\r\n }\r\n\r\n async getMany<T>(keys: string[]): Promise<Record<string, T | null>> {\r\n const startAt = performance.now();\r\n\r\n const data = await this.cache.getMany<T>(keys);\r\n\r\n const time = performance.now() - startAt;\r\n const timePerKey = time / keys.length;\r\n\r\n const miss = keys.filter(key => data[key] === undefined || data[key] === null).length;\r\n const hits = keys.length - miss;\r\n\r\n this.countMetrics.missCount += miss;\r\n this.countMetrics.hitCount += hits;\r\n this.totalTimeMetrics.missTime += miss * timePerKey;\r\n this.totalTimeMetrics.hitTime += hits * timePerKey;\r\n\r\n this.logger?.debug(this.name, '[getMany]', 'hits =', hits, 'misses = ', miss, 'timeMS =', time);\r\n\r\n return data;\r\n }\r\n\r\n async setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.setMany(data, options);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n const sets = Object.keys(data).length;\r\n\r\n this.countMetrics.setCount += sets;\r\n this.totalTimeMetrics.setTime += time;\r\n\r\n this.logger?.debug(this.name, '[setMany]', 'sets =', sets, 'timeMS =', time);\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n const startAt = performance.now();\r\n\r\n await this.cache.deleteMany(keys);\r\n\r\n const time = performance.now() - startAt;\r\n\r\n this.countMetrics.deleteCount += keys.length;\r\n this.totalTimeMetrics.deleteTime += time;\r\n\r\n this.logger?.debug(this.name, '[deleteMany]', 'deletes =', keys.length, 'timeMS =', time);\r\n }\r\n\r\n getMetrics(): CacheMetrics {\r\n const count = this.countMetrics;\r\n const time = this.totalTimeMetrics;\r\n\r\n return {\r\n ...count,\r\n missTime: count.missCount === 0 ? 0 : time.missTime / count.missCount,\r\n hitTime: count.hitCount === 0 ? 0 : time.hitTime / count.hitCount,\r\n loadTime: count.loadCount === 0 ? 0 : time.loadTime / count.loadCount,\r\n setTime: count.setCount === 0 ? 0 : time.setTime / count.setCount,\r\n deleteTime: count.deleteCount === 0 ? 0 : time.deleteTime / count.deleteCount,\r\n };\r\n }\r\n\r\n resetMetrics(): void {\r\n this.countMetrics = {\r\n missCount: 0,\r\n hitCount: 0,\r\n loadCount: 0,\r\n setCount: 0,\r\n deleteCount: 0,\r\n };\r\n this.totalTimeMetrics = {\r\n missTime: 0,\r\n hitTime: 0,\r\n loadTime: 0,\r\n setTime: 0,\r\n deleteTime: 0,\r\n };\r\n\r\n this.logger?.debug(this.name, '[resetMetrics]');\r\n }\r\n\r\n}\r\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cachimbo",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "author": "Guilherme Chaguri",
5
5
  "license": "Apache-2.0",
6
6
  "description": "An advanced caching library that allows you to layer different strategies in order to maximize the performance.",
@@ -14,7 +14,6 @@
14
14
  "test": "vitest",
15
15
  "coverage": "vitest run --coverage --coverage.include=src/**/*.ts",
16
16
  "prepack": "tsdown",
17
-
18
17
  "sample:no-cache": "tsx ./samples/1-no-cache.ts",
19
18
  "sample:redis-cache": "tsx ./samples/2-redis-cache.ts",
20
19
  "sample:ttl-cache": "tsx ./samples/3-ttl-cache.ts",
@@ -60,16 +59,17 @@
60
59
  }
61
60
  },
62
61
  "dependencies": {
63
- "@isaacs/ttlcache": "^2.1.3",
62
+ "@isaacs/ttlcache": "^2.1.4",
64
63
  "lru-cache": "^11.2.4"
65
64
  },
66
65
  "devDependencies": {
67
- "@cloudflare/workers-types": "^4.20251229.0",
66
+ "@cloudflare/workers-types": "^4.20260103.0",
68
67
  "@redis/client": "^5.10.0",
69
68
  "@types/memjs": "^1.3.3",
70
69
  "@types/node": "^24.10.4",
71
70
  "@valkey/valkey-glide": "^2.2.1",
72
71
  "@vitest/coverage-v8": "^4.0.16",
72
+ "hazelcast-client": "^5.3.0",
73
73
  "ioredis": "^5.8.2",
74
74
  "iovalkey": "^0.3.3",
75
75
  "keyv": "^5.5.5",