UNPKG

ai-patterns

Version:

Production-ready TypeScript patterns to build solid and robust AI applications. Retry logic, circuit breakers, rate limiting, human-in-the-loop escalation, prompt versioning, response validation, context window management, and more—all with complete type

128 lines 3.9 kB
"use strict"; /** * Debounce Pattern - Execute after silence period */ Object.defineProperty(exports, "__esModule", { value: true }); exports.debounce = void 0; exports.defineDebounce = defineDebounce; const common_1 = require("../types/common"); /** * Define a debounced function * * @example * ```typescript * const saveData = defineDebounce({ * execute: async () => await api.save(), * wait: 500, * maxWait: 2000 * }); * * saveData(); // Will execute after 500ms of silence * ``` */ function defineDebounce(options) { const { execute: fn, wait, maxWait, leading = false, logger = common_1.defaultLogger, onDebounced, onExecute, } = options; // Support both 'wait' and 'delayMs' for compatibility const delay = wait ?? options.delayMs ?? 300; let timeoutId = null; let maxWaitTimeoutId = null; let lastInvokeTime = 0; let lastArgs = null; let lastThis = null; let result; let pending = false; let pendingResolvers = []; const invokeFunction = async () => { const args = lastArgs; const thisArg = lastThis; const resolvers = [...pendingResolvers]; lastArgs = null; lastThis = null; lastInvokeTime = Date.now(); pending = false; pendingResolvers = []; if (onExecute) { onExecute(...args); } logger.info("Executing debounced function"); result = await fn.apply(thisArg, args); // Resolve all pending promises resolvers.forEach(resolve => resolve(result)); return result; }; const cancelMaxWaitTimer = () => { if (maxWaitTimeoutId) { clearTimeout(maxWaitTimeoutId); maxWaitTimeoutId = null; } }; const cancelTimer = () => { if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } }; const debounced = function (...args) { const time = Date.now(); const isInvoking = leading && !pending; lastArgs = args; lastThis = this; pending = true; if (isInvoking) { return invokeFunction(); } cancelTimer(); if (onDebounced) { onDebounced(); } return new Promise((resolve) => { // Add this resolver to pending resolvers pendingResolvers.push(resolve); // Set timeout for this debounced call (always create new timeout after cancel) timeoutId = setTimeout(async () => { timeoutId = null; cancelMaxWaitTimer(); await invokeFunction(); }, delay); // Max wait timer if (maxWait !== undefined && !maxWaitTimeoutId) { const timeSinceLastInvoke = time - lastInvokeTime; const timeToMaxWait = maxWait - timeSinceLastInvoke; if (timeToMaxWait > 0) { maxWaitTimeoutId = setTimeout(async () => { maxWaitTimeoutId = null; cancelTimer(); await invokeFunction(); }, timeToMaxWait); } } }); }; debounced.cancel = () => { cancelTimer(); cancelMaxWaitTimer(); lastArgs = null; lastThis = null; pending = false; pendingResolvers = []; logger.info("Debounced function cancelled"); }; debounced.flush = async () => { if (!pending) { return result; } cancelTimer(); cancelMaxWaitTimer(); return await invokeFunction(); }; debounced.pending = () => { return pending; }; return debounced; } /** * @deprecated Use `defineDebounce` instead * @see defineDebounce */ exports.debounce = defineDebounce; //# sourceMappingURL=debounce.js.map