import type { AsyncFunc } from '../../types.ts'; import type { MemoizeOptions, EnhancedMemoizedFunction } from './types.ts'; /** * Memoizes an async function with intelligent caching, LRU eviction, and stale-while-revalidate. * * **What it does:** * - Caches async function results with configurable TTL * - Deduplicates concurrent calls with the same arguments (thundering herd protection) * - LRU eviction when cache reaches maxSize * - Optional stale-while-revalidate pattern for fast responses with fresh data * - Pluggable cache adapters (Map by default, Redis/Memcached via custom adapters) * - Background cleanup of expired entries * - WeakRef support for memory-sensitive scenarios * * **When to use:** * - Expensive async operations (database queries, API calls, computations) * - Functions called frequently with the same arguments * - Need to prevent duplicate concurrent executions * - Want fast responses with eventually-fresh data (stale-while-revalidate) * * **Performance notes:** * - Cache hit path is optimized for minimal allocations * - Default key generation: O(n) in argument structure size * - For hot paths, provide custom generateKey extracting only discriminating fields * * @template T - Async function type * @param fn - Async function to memoize * @param opts - Memoization options * @returns Enhanced memoized function with cache management methods * * @example * // Basic usage * const fetchUser = async (id: string) => database.users.findById(id); * const getUser = memoize(fetchUser); * * // Three concurrent calls → one database query * const [user1, user2, user3] = await Promise.all([ * getUser("42"), * getUser("42"), * getUser("42") * ]); * * @example * // With stale-while-revalidate * const fetchPrices = async (symbol: string) => api.getPrice(symbol); * const getPrice = memoize(fetchPrices, { * ttl: 60000, // Expire after 1 minute * staleIn: 30000, // Consider stale after 30 seconds * staleTimeout: 1000 // Wait max 1 second for fresh data * }); * * // Returns stale data immediately if fresh fetch takes > 1 second * const price = await getPrice("AAPL"); * * @example * // With custom key and cache management * const search = async (query: string, opts: SearchOptions) => api.search(query, opts); * const memoizedSearch = memoize(search, { * generateKey: (query) => query, // Only cache by query, ignore opts * maxSize: 100, * ttl: 300000 // 5 minutes * }); * * // Cache management * memoizedSearch.cache.stats(); // { hits: 10, misses: 3, hitRate: 0.77, ... } * memoizedSearch.cache.clear(); // Clear all cached results * memoizedSearch.cache.delete(someKey); // Remove specific entry * * @example * // Conditional caching - bypass cache for specific requests * const fetchData = async (url: string, opts?: { bustCache?: boolean }) => api.get(url); * const smartFetch = memoize(fetchData, { * shouldCache: (url, opts) => !opts?.bustCache, * ttl: 60000 * }); * * // This call uses cache * await smartFetch('/api/data'); * * // This call bypasses cache and executes directly (still deduped) * await smartFetch('/api/data', { bustCache: true }); */ export declare const memoize: >(fn: T, opts?: MemoizeOptions) => EnhancedMemoizedFunction;