@daiso-tech/core
Version:
The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.
253 lines (252 loc) • 9.9 kB
TypeScript
/**
* @module Cache
*/
import { type CacheEventMap } from "../../cache/contracts/cache.events.js";
import { type IEventListenable } from "../../event-bus/contracts/_module.js";
import { type ITimeSpan } from "../../time-span/contracts/_module.js";
import { type AsyncLazyable, type NoneFunc } from "../../utilities/_module.js";
/**
* The `ICacheListenable` contract provides a way to listen to cache operation events and track state changes.
* Subscribe to cache events to monitor entry additions, retrievals, updates, evictions, and expirations.
*
* IMPORT_PATH: `"@daiso-tech/core/cache/contracts"`
* @group Contracts
*/
export type ICacheListenable<TType = unknown> = IEventListenable<CacheEventMap<TType>>;
/**
* Configuration settings for cache write operations.
*
* IMPORT_PATH: `"@daiso-tech/core/cache/contracts"`
* @group Contracts
*/
export type CacheWriteSettings = {
/**
* Time-to-live (TTL) duration for cached entries.
* When set, entries will automatically expire after this duration.
* Pass `null` to cache entries without automatic expiration.
*/
ttl?: ITimeSpan | null;
/**
* Random jitter factor (0-1) to add variance to expiration times.
* Prevents thundering herd problems when many entries expire simultaneously.
* A value of 0.1 adds ±10% randomness to the TTL.
*/
jitter?: number;
/**
* Used internally for testing to control random number generation.
*
* @internal
*/
_mathRandom?: () => number;
};
/**
* The `IReadableCache` contract defines a read-only interface for accessing cached key-value pairs.
* It provides methods to retrieve values independent of the underlying cache storage backend (Redis, Memcached, database, etc.).
* Use this contract when you need read-only access to cache data without mutation capabilities.
*
* IMPORT_PATH: `"@daiso-tech/core/cache/contracts"`
* @group Contracts
*/
export type IReadableCache<TType = unknown> = {
/**
* Checks if a key exists in the cache.
*
* @param key - The cache key to check
* @returns true if the key exists, false otherwise
*/
exists(key: string): Promise<boolean>;
/**
* Checks if a key does not exist in the cache.
*
* @param key - The cache key to check
* @returns true if the key is missing, false if it exists
*/
missing(key: string): Promise<boolean>;
/**
* Retrieves a cached value by key.
*
* @param key - The cache key to retrieve
* @returns The cached value, or null if the key is not found or has expired
* @throws {ValidationError}
*/
get(key: string): Promise<TType | null>;
/**
* Retrieves a cached value by key, throwing an error if not found.
*
* @param key - The cache key to retrieve
* @returns The cached value
* @throws {KeyNotFoundCacheError} If the key is not found or has expired
* @throws {ValidationError}
*/
getOrFail(key: string): Promise<TType>;
/**
* Retrieves a cached value with a default fallback.
*
* @param key - The cache key to retrieve
* @param defaultValue - Default value to return if key is not found. Can be a static value, sync function, or async function.
* @returns The cached value, or the default value if the key is not found
* @throws {ValidationError}
*/
getOr(key: string, defaultValue: AsyncLazyable<NoneFunc<TType>>): Promise<TType>;
};
/**
* Configuration settings for cache get-or-add operations.
* Extends {@link CacheWriteSettings | `CacheWriteSettings`} to support atomic read-compute-write patterns.
*
* IMPORT_PATH: `"@daiso-tech/core/cache/contracts"`
* @group Contracts
*/
export type GetOrAddSettings = CacheWriteSettings & {
/**
* Enable distributed locking for the get-or-add operation.
* When enabled, uses a lock to ensure only one client computes and caches the value,
* preventing cache stampedes when multiple clients request the same missing key.
*
* @default false
*/
enableLocking?: boolean;
};
/**
* The `ICacheBase` contract defines a way for storing and reading as key-value pairs independent of data storage.
*
* IMPORT_PATH: `"@daiso-tech/core/cache/contracts"`
* @group Contracts
*/
export type ICacheBase<TType = unknown> = IReadableCache<TType> & {
/**
* The `getAndRemove` method returns the value when `key` is found otherwise null will be returned.
* The key will be removed after it is returned.
* @throws {ValidationError}
*/
getAndRemove(key: string): Promise<TType | null>;
/**
* The `getOrAdd` method will retrieve the given `key` if found otherwise `valueToAdd` will be added and returned.
*
* @param valueToAdd - can be regular value, sync or async {@link Invokable | `Invokable`} value and {@link Promise | `Promise`} value.
* @throws {ValidationError}
*/
getOrAdd(key: string, valueToAdd: AsyncLazyable<NoneFunc<TType>>, settings?: GetOrAddSettings): Promise<TType>;
/**
* The `add` method adds a `key` with given `value` when key doesn't exists.
*
* @param settings.ttl - If null is passed, the item will not expire.
*
* @returns Returns true when key doesn't exists otherwise false will be returned.
* @throws {ValidationError}
*/
add(key: string, value: TType, settings?: CacheWriteSettings): Promise<boolean>;
/**
* The `addOrFail` method adds a `key` with given `value` when key doesn't exists.
* Throws an error if the `key` exists.
*
* @throws {KeyExistsCacheError}
* @throws {ValidationError}
*/
addOrFail(key: string, value: TType, settings?: CacheWriteSettings): Promise<void>;
/**
* The `put` methods upsert the given key and replaces the ttl when updated.
*
* @param settings.ttl - If null is passed, the item will not expire.
*
* @returns Returns true if the `key` where replaced otherwise false is returned.
* @throws {ValidationError}
*/
put(key: string, value: TType, settings?: CacheWriteSettings): Promise<boolean>;
/**
* The `update` method updates the given `key` with given `value`.
*
* @returns Returns true if the `key` where updated otherwise false will be returned.
* @throws {ValidationError}
*/
update(key: string, value: TType): Promise<boolean>;
/**
* The `updateOrFail` method updates the given `key` with given `value`.
* Thorws error if the `key` is not found.
*
* @throws {KeyNotFoundCacheError}
* @throws {ValidationError}
*/
updateOrFail(key: string, value: TType): Promise<void>;
/**
* The `increment` method increments the given `key` with given `value`.
* An error will thrown if the value is not a number.
*
* @param value - If not defined then it will be defaulted to 1.
*
* @returns Returns true if the `key` where incremented otherwise false will be returned.
*
* @throws {TypeError}
* @throws {ValidationError}
*/
increment(key: string, value?: Extract<TType, number>): Promise<boolean>;
/**
* The `incrementOrFail` method increments the given `key` with given `value`.
* An error will thrown if the value is not a number or if the key is not found.
*
* @param value - If not defined then it will be defaulted to 1.
*
* @throws {KeyNotFoundCacheError}
* @throws {TypeError}
* @throws {ValidationError}
*/
incrementOrFail(key: string, value?: Extract<TType, number>): Promise<void>;
/**
* The `decrement` method decrements the given `key` with given `value`.
* An error will thrown if the value is not a number.
*
* @param value - If not defined then it will be defaulted to 1.
*
* @returns Returns true if the `key` where decremented otherwise false will be returned.
*
* @throws {TypeError}
* @throws {ValidationError}
*/
decrement(key: string, value?: Extract<TType, number>): Promise<boolean>;
/**
* The `decrementOrFail` method decrements the given `key` with given `value`.
* An error will thrown if the value is not a number or if the key is not found.
*
* @param value - If not defined then it will be defaulted to 1.
*
* @throws {KeyNotFoundCacheError}
* @throws {TypeError}
* @throws {ValidationError}
*/
decrementOrFail(key: string, value?: Extract<TType, number>): Promise<void>;
/**
* The `remove` method removes the given `key`.
*
* @returns Returns true if the key is found otherwise false is returned.
*/
remove(key: string): Promise<boolean>;
/**
* The `removeOrFail` method removes the given `key`.
* Throws an error if the key is not found.
*
* @throws {KeyNotFoundCacheError}
*/
removeOrFail(key: string): Promise<void>;
/**
* The `removeMany` method removes many keys.
*
* @param keys - The param items can be a string or an `Iterable` of strings.
* If the param items are an `Iterable`, it will be joined into a single string.
* Think of an `Iterable` as representing a path.
*
* @returns Returns true if one of the keys where deleted otherwise false is returned.
*/
removeMany(keys: Iterable<string>): Promise<boolean>;
/**
* The `clear` method removes all the keys in the cache. If a cache is in a group then only the keys part of the group will be removed.
*/
clear(): Promise<void>;
};
/**
* The `ICache` contract defines a way for as key-value pairs independent of data storage and listening to operation events.
*
* IMPORT_PATH: `"@daiso-tech/core/cache/contracts"`
* @group Contracts
*/
export type ICache<TType = unknown> = ICacheBase<TType> & {
readonly events: ICacheListenable<TType>;
};