import type { IsoDuration } from 'iso-time'; import { type NotUndefined } from 'type-fns'; import type { CacheMetaChoice, CacheMetaOutput, HasCacheConditionals, SimpleCache, WithSimpleCacheConditionOption } from '../../domain.objects/SimpleCache'; import { type WithSimpleCacheChoice } from '../../domain.operations/options/getCacheFromCacheChoice'; import { type KeySerializationMethod } from '../../domain.operations/serde/defaults'; export type CacheableLogicSync = (...args: any[]) => any; /** * return type depends on meta value */ type WithMetaReturn, M extends 'include' | 'exclude' | undefined> = M extends 'include' ? (...args: Parameters) => { output: ReturnType; cached: CacheMetaOutput; } : L; /** * options to configure cache for use with-simple-cache */ export interface WithSimpleCacheOptions< /** * the logic we wrap with cache */ L extends CacheableLogicSync, /** * the cache type */ C extends SimpleCache, /** * whether to include cache metadata in the return value */ M extends CacheMetaChoice | undefined = undefined> { /** * the cache to persist outputs * * accepts: * - direct cache instance * - extraction function: (_input, context) => context.cache */ cache: WithSimpleCacheChoice, C>; /** * custom serialization for cache keys and values * * use when the logic's return type differs from the cache's stored type */ serialize?: { /** * serialize input args to a cache key string * * @param input - the first argument passed to the wrapped function * @param context - the second argument passed to the wrapped function (if any) * @returns a string key for cache lookup * * @default JSON.stringify(input) */ key?: KeySerializationMethod>; /** * serialize the logic's output before cache set * * @param output - the return value from the wrapped function * @returns the value to store in cache (must match cache's value type) * * @default identity (no transformation) */ value?: (output: ReturnType) => NotUndefined>; }; /** * custom deserialization for cached values * * use when the cache's stored type differs from the logic's return type */ deserialize?: { /** * deserialize cached value back to the logic's return type * * @param cached - the value retrieved from cache * @returns the value to return to the caller (must match logic's return type) * * @default identity (no transformation) */ value?: (cached: NotUndefined>) => ReturnType; }; /** * time-to-live for cached values * * @example { seconds: 60 } * @example { minutes: 5 } * @example { hours: 1 } * @example null // no expiration * * @default undefined (cache decides) */ expiration?: IsoDuration | null; /** * whether to bypass the cache for get or set operations */ bypass?: { /** * whether to bypass the cache for the get * * note * - equivalent to the result not already cached * * default * - process.env.CACHE_BYPASS_GET ? process.env.CACHE_BYPASS_GET === 'true' : process.env.CACHE_BYPASS === 'true' */ get?: (...args: Parameters) => boolean; /** * whether to bypass the cache for the set * * note * - keeps whatever the previously cached value was, returns the new value * * default * - process.env.CACHE_BYPASS_SET ? process.env.CACHE_BYPASS_SET === 'true' : process.env.CACHE_BYPASS === 'true' */ set?: (...args: Parameters) => boolean; }; /** * whether to include cache metadata in the return value * * - 'exclude' (default): returns the logic's return value directly * - 'include': returns { output, cached } where cached.uri / cached.version are present per capability * * note * - 'include' is only available when the cache has a uri or conditional-write capability */ meta?: M; /** * a version precondition that gates the cache set (atomic conditional write) * * note * - available only when the cache HasCacheConditionals (a plain cache rejects it at compile time) * - the get→compute→set flow calls cache.set(key, value, { condition }); a precondition miss * throws SimpleCacheConditionError, which `exception` governs (throw by default, or ignore + converge) */ condition?: HasCacheConditionals extends true ? WithSimpleCacheConditionOption : never; } /** * a wrapper which uses a synchronous cache to cache the result of the wrapped logic * * for example: * ```ts * const getApiResult = withSimpleCache(({ name, number }) => axios.get(URL, { name, number })); * const result1 = getApiResult({ name: 'casey', number: 821 }); // calls the api, puts promise of results into cache, returns that promise * const result2 = getApiResult({ name: 'casey', number: 821 }); // returns the same promise from above, because it was found in cache - since same input as request above was used * expect(result1).toBe(result2); // same exact object - the promise * expect(await result1).toBe(await result2); // same exact object - the result of the promise * ``` */ export declare const withSimpleCache: , M extends CacheMetaChoice | undefined = undefined>(logic: L, { cache: cacheOption, serialize: { key: serializeKey, value: serializeValue, }, deserialize: { value: deserializeValue, }, expiration, bypass, meta, condition, }: WithSimpleCacheOptions) => WithMetaReturn; export {};