import Logger from '../core/logging/logger'; class CSQMethodFilter { private static instance: CSQMethodFilter; private isCSQEnabled = false; private hasStartBeenCalled = false; private loggedMessages: Map = new Map(); private readonly DEBOUNCE_TIME = 1000; private constructor() {} public static getInstance(): CSQMethodFilter { if (!CSQMethodFilter.instance) { CSQMethodFilter.instance = new CSQMethodFilter(); } return CSQMethodFilter.instance; } /** * Debounced warning logger that prevents the same message from being logged * multiple times within the debounce time window * @param message - The warning message to log */ private debouncedWarn(message: string): void { const now = Date.now(); const lastLoggedTime = this.loggedMessages.get(message); if (!lastLoggedTime || now - lastLoggedTime >= this.DEBOUNCE_TIME) { Logger.warn(message); this.loggedMessages.set(message, now); } } /** * Manually clear a specific logged message from the debounce cache * Useful for testing or forcing a re-log of a specific message * @param message - The message to clear from cache */ public clearLoggedMessage(message: string): void { this.loggedMessages.delete(message); } public callStartMethod(start: () => void, origin: 'CSQ' | 'default'): void { this.hasStartBeenCalled = true; if (origin === 'CSQ') { this.isCSQEnabled = true; } else { this.isCSQEnabled = false; } start(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any public executeMethodIfAllowed any>( originalMethod: T, origin: 'CSQ' | 'default', forceCall = false ): (...args: Parameters) => ReturnType | undefined { return (...args: Parameters): ReturnType | undefined => { if (forceCall) { return originalMethod(...args); } if (!this.hasStartBeenCalled && origin === 'CSQ') { this.debouncedWarn( `Cannot call ${originalMethod.name}(): The SDK has not been started yet. Please call start() first.` ); return undefined; } if (this.isCSQEnabled && origin === 'CSQ') { return originalMethod(...args); } if (!this.isCSQEnabled && origin === 'default') { return originalMethod(...args); } else { this.debouncedWarn( `The SDK method (${ originalMethod.name }) you are trying to call is from the ${ origin === 'CSQ' ? 'CSQ' : 'legacy' } SDK` ); return undefined; } }; } public warnIfDisabled( origin: 'CSQ' | 'default', componentName: string ): void { if (!this.hasStartBeenCalled && origin === 'CSQ') { this.debouncedWarn( `Cannot use ${componentName}: The SDK has not been started yet. Please call start() first.` ); return; } if (this.isCSQEnabled && origin === 'default') { this.debouncedWarn( `${componentName} component or method you are trying to call is from the legacy SDK, but the CSQ SDK is currently enabled.` ); } else if (!this.isCSQEnabled && origin === 'CSQ') { this.debouncedWarn( `${componentName} component or method you are trying to call is from the CSQ SDK, but the legacy SDK is currently enabled.` ); } } /** * Reset the filter state for testing purposes */ public resetForTesting(): void { this.isCSQEnabled = false; this.hasStartBeenCalled = false; this.loggedMessages.clear(); } } export default CSQMethodFilter.getInstance();