UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

270 lines • 11.2 kB
import { nanoid } from 'nanoid'; export var FaultType; (function (FaultType) { // Network Faults FaultType["NETWORK_LATENCY"] = "network_latency"; FaultType["NETWORK_TIMEOUT"] = "network_timeout"; FaultType["NETWORK_DISCONNECTION"] = "network_disconnection"; FaultType["PACKET_LOSS"] = "packet_loss"; // Resource Faults FaultType["MEMORY_PRESSURE"] = "memory_pressure"; FaultType["CPU_SPIKE"] = "cpu_spike"; FaultType["DISK_SPACE"] = "disk_space"; // Service Faults FaultType["DATABASE_ERROR"] = "database_error"; FaultType["API_DOWNTIME"] = "api_downtime"; FaultType["SERVICE_DEGRADATION"] = "service_degradation"; })(FaultType || (FaultType = {})); export class FaultInjectionEngine { activeFaults = new Map(); sessionData = { injectedFaults: [] }; constructor() { // No longer requires page in constructor } async injectFault(page, fault) { const faultId = nanoid(); const timestamp = Date.now(); // Add to active faults first this.activeFaults.set(faultId, { id: faultId, fault, timestamp }); this.sessionData.injectedFaults.push({ id: faultId, fault, timestamp }); switch (fault.type) { case FaultType.NETWORK_LATENCY: await this.injectNetworkLatency(page, fault, faultId); break; case FaultType.NETWORK_TIMEOUT: await this.injectNetworkTimeout(page, fault, faultId); break; case FaultType.NETWORK_DISCONNECTION: await this.injectNetworkDisconnection(page, fault, faultId); break; case FaultType.PACKET_LOSS: await this.injectPacketLoss(page, fault, faultId); break; case FaultType.MEMORY_PRESSURE: await this.injectMemoryPressure(page, fault, faultId); break; case FaultType.CPU_SPIKE: await this.injectCPUSpike(page, fault, faultId); break; case FaultType.DISK_SPACE: await this.injectDiskSpace(page, fault, faultId); break; case FaultType.DATABASE_ERROR: await this.injectDatabaseError(page, fault, faultId); break; case FaultType.API_DOWNTIME: await this.injectAPIDowntime(page, fault, faultId); break; case FaultType.SERVICE_DEGRADATION: await this.injectServiceDegradation(page, fault, faultId); break; } return faultId; } async injectNetworkLatency(page, fault, faultId) { const handler = async (route) => { await new Promise(resolve => setTimeout(resolve, fault.config.latencyMs || 0)); await route.continue(); }; await page.route(fault.config.urlPattern, handler); this.activeFaults.get(faultId).handler = handler; } async injectNetworkTimeout(page, fault, faultId) { const handler = async (route) => { await new Promise(resolve => setTimeout(resolve, fault.config.timeoutMs || 5000)); await route.abort('timedout'); }; await page.route(fault.config.urlPattern, handler); this.activeFaults.get(faultId).handler = handler; } async injectNetworkDisconnection(page, fault, faultId) { const handler = async (route) => { await route.abort('connectionfailed'); }; await page.route(fault.config.urlPattern, handler); this.activeFaults.get(faultId).handler = handler; } async injectPacketLoss(page, fault, faultId) { const handler = async (route) => { const shouldDrop = Math.random() * 100 < (fault.config.lossPercentage || 0); if (shouldDrop) { await route.abort('connectionfailed'); } else { await route.continue(); } }; await page.route(fault.config.urlPattern, handler); this.activeFaults.get(faultId).handler = handler; } async injectMemoryPressure(page, fault, faultId) { await page.evaluate(({ limitMB, id }) => { // Simulate memory pressure by allocating arrays const arrays = []; const targetBytes = (limitMB || 100) * 1024 * 1024; let allocated = 0; const interval = setInterval(() => { try { // Allocate 1MB chunks const chunk = new Array(1024 * 1024 / 8); arrays.push(chunk); allocated += 1024 * 1024; if (allocated >= targetBytes) { clearInterval(interval); } } catch (e) { clearInterval(interval); } }, 10); // Store cleanup function window.__faultCleanup = window.__faultCleanup || {}; window.__faultCleanup[id] = () => { clearInterval(interval); arrays.length = 0; }; }, { limitMB: fault.config.limitMB, id: faultId }); } async injectCPUSpike(page, fault, faultId) { await page.evaluate((config) => { const startTime = Date.now(); const duration = config.durationMs || 1000; const intensity = config.intensity || 0.8; const spike = () => { const now = Date.now(); if (now - startTime < duration) { // CPU intensive operation const endTime = now + (16 * intensity); // ~16ms per frame while (Date.now() < endTime) { Math.sqrt(Math.random()); } requestAnimationFrame(spike); } }; requestAnimationFrame(spike); }, fault.config); } async injectDiskSpace(page, fault, faultId) { await page.evaluate((availableKB) => { // Override storage quota APIs if ('storage' in navigator && 'estimate' in navigator.storage) { const originalEstimate = navigator.storage.estimate; navigator.storage.estimate = async () => { const result = await originalEstimate.call(navigator.storage); return { ...result, quota: (availableKB || 1024) * 1024, usage: Math.min(result.usage || 0, (availableKB || 1024) * 1024 * 0.9) }; }; } }, fault.config.availableKB); } async injectDatabaseError(page, fault, faultId) { const handler = async (route) => { const shouldError = Math.random() < (fault.config.errorRate || 0.5); if (shouldError) { await route.fulfill({ status: 500, contentType: 'application/json', body: JSON.stringify({ error: 'Database connection failed' }) }); } else { await route.continue(); } }; await page.route(fault.config.urlPattern, handler); this.activeFaults.get(faultId).handler = handler; } async injectAPIDowntime(page, fault, faultId) { const handler = async (route) => { await route.fulfill({ status: fault.config.statusCode || 503, contentType: 'application/json', body: JSON.stringify({ error: 'Service temporarily unavailable' }) }); }; await page.route(fault.config.urlPattern, handler); this.activeFaults.get(faultId).handler = handler; } async injectServiceDegradation(page, fault, faultId) { const handler = async (route) => { const degradationFactor = fault.config.degradationFactor || 0.5; const delay = Math.random() * 5000 * degradationFactor; await new Promise(resolve => setTimeout(resolve, delay)); // Randomly drop some requests if (Math.random() < degradationFactor * 0.1) { await route.abort('failed'); } else { await route.continue(); } }; await page.route(fault.config.urlPattern, handler); this.activeFaults.get(faultId).handler = handler; } async removeFault(page, faultId) { const activeFault = this.activeFaults.get(faultId); if (!activeFault) return; // Clean up page-level changes if (activeFault.fault.type === FaultType.MEMORY_PRESSURE) { await page.evaluate((id) => { if (window.__faultCleanup && window.__faultCleanup[id]) { window.__faultCleanup[id](); delete window.__faultCleanup[id]; } }, faultId); } this.activeFaults.delete(faultId); } async clearAllFaults(page) { const faultIds = Array.from(this.activeFaults.keys()); for (const faultId of faultIds) { await this.removeFault(page, faultId); } } getActiveFaults() { return Array.from(this.activeFaults.values()); } getSessionData() { return this.sessionData; } async generateTestScenarios() { return [ { name: 'Network Resilience', faults: [ { type: FaultType.NETWORK_LATENCY, config: { latencyMs: 2000, urlPattern: '**/api/**' } }, { type: FaultType.PACKET_LOSS, config: { lossPercentage: 10, urlPattern: '**/api/**' } } ], expectedBehavior: 'Application should show loading states and retry failed requests' }, { name: 'Resource Constraints', faults: [ { type: FaultType.MEMORY_PRESSURE, config: { limitMB: 50 } }, { type: FaultType.CPU_SPIKE, config: { durationMs: 3000, intensity: 0.9 } } ], expectedBehavior: 'Application should remain responsive and not crash' }, { name: 'Service Degradation', faults: [ { type: FaultType.API_DOWNTIME, config: { urlPattern: '**/auth/**', statusCode: 503 } }, { type: FaultType.DATABASE_ERROR, config: { urlPattern: '**/api/data/**', errorRate: 0.3 } } ], expectedBehavior: 'Application should gracefully handle errors and show appropriate messages' }, { name: 'Complete Outage', faults: [ { type: FaultType.NETWORK_DISCONNECTION, config: { urlPattern: '**' } } ], expectedBehavior: 'Application should work offline or show clear offline state' } ]; } } //# sourceMappingURL=fault-injection-engine.js.map