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

433 lines • 19.2 kB
/** * Flutter Platform Integration Module * * Handles platform channels, browser compatibility, asset loading, and Flutter web-specific features. * This module provides comprehensive platform integration insights and issue detection. */ export class FlutterPlatformIntegration { page; platformChannels = new Map(); gestureConflicts = []; async attachToPage(page) { this.page = page; await this.setupPlatformChannelMonitoring(); await this.setupGestureTracking(); } async getBrowserCompatibility() { if (!this.page) { return { browser: 'unknown', version: 'unknown', flutterSupport: 'none', missingFeatures: [], performanceIssues: [], recommendations: [] }; } try { const compatibility = await this.page.evaluate(() => { const userAgent = navigator.userAgent; let browser = 'unknown'; let version = 'unknown'; // Detect browser if (userAgent.includes('Chrome')) { browser = 'Chrome'; const match = userAgent.match(/Chrome\/(\d+\.\d+)/); version = match ? match[1] : 'unknown'; } else if (userAgent.includes('Firefox')) { browser = 'Firefox'; const match = userAgent.match(/Firefox\/(\d+\.\d+)/); version = match ? match[1] : 'unknown'; } else if (userAgent.includes('Safari')) { browser = 'Safari'; const match = userAgent.match(/Version\/(\d+\.\d+)/); version = match ? match[1] : 'unknown'; } else if (userAgent.includes('Edge')) { browser = 'Edge'; const match = userAgent.match(/Edge\/(\d+\.\d+)/); version = match ? match[1] : 'unknown'; } // Assess Flutter support const hasCanvasKit = !!window.CanvasKit; const hasWebAssembly = typeof WebAssembly !== 'undefined'; const hasWebGL = !!document.createElement('canvas').getContext('webgl'); const hasIntersectionObserver = 'IntersectionObserver' in window; const hasResizeObserver = 'ResizeObserver' in window; let flutterSupport = 'none'; const missingFeatures = []; const performanceIssues = []; const recommendations = []; if (hasWebAssembly && hasWebGL) { flutterSupport = 'full'; } else if (hasWebAssembly || hasWebGL) { flutterSupport = 'partial'; } // Check for missing features if (!hasWebAssembly) { missingFeatures.push('WebAssembly'); recommendations.push('Update to a modern browser that supports WebAssembly'); } if (!hasWebGL) { missingFeatures.push('WebGL'); recommendations.push('Enable hardware acceleration in browser settings'); } if (!hasIntersectionObserver) { missingFeatures.push('IntersectionObserver'); recommendations.push('Consider using polyfills for older browsers'); } if (!hasResizeObserver) { missingFeatures.push('ResizeObserver'); } // Browser-specific performance issues if (browser === 'Safari') { performanceIssues.push('Safari has known issues with WebAssembly performance'); recommendations.push('Consider using HTML renderer for Safari users'); } if (browser === 'Firefox') { performanceIssues.push('Firefox may have slower CanvasKit rendering'); recommendations.push('Monitor performance metrics on Firefox'); } return { browser, version, flutterSupport, missingFeatures, performanceIssues, recommendations }; }); return compatibility || { browser: 'unknown', version: 'unknown', flutterSupport: 'none', missingFeatures: [], performanceIssues: [], recommendations: [] }; } catch (error) { return { browser: 'unknown', version: 'unknown', flutterSupport: 'none', missingFeatures: [], performanceIssues: [], recommendations: [] }; } } async analyzeAssetLoading() { if (!this.page) { return this.getDefaultAssetAnalysis(); } try { const analysis = await this.page.evaluate(() => { const resources = performance.getEntriesByType('resource'); const assets = []; const fonts = []; resources.forEach(resource => { const name = resource.name.split('/').pop() || resource.name; const size = resource.transferSize || 0; const loadTime = resource.duration; const cached = resource.transferSize === 0 && resource.decodedBodySize > 0; if (resource.name.includes('assets/') || resource.name.includes('images/')) { const optimized = resource.name.includes('.webp') || resource.name.includes('.avif') || (resource.name.includes('.png') && size < 50000); assets.push({ name, size, loadTime, cached, optimized }); } else if (resource.name.includes('.ttf') || resource.name.includes('.otf') || resource.name.includes('.woff') || resource.name.includes('fonts/')) { fonts.push({ name, size, loadTime, cached }); } }); const totalAssets = assets.length + fonts.length; const totalSize = assets.reduce((sum, asset) => sum + asset.size, 0) + fonts.reduce((sum, font) => sum + font.size, 0); const totalLoadTime = Math.max(...assets.map(asset => asset.loadTime), ...fonts.map(font => font.loadTime)); const unoptimizedAssets = assets.filter(asset => !asset.optimized).length; return { assets, fonts, totalAssets, totalSize, totalLoadTime: isFinite(totalLoadTime) ? totalLoadTime : 0, unoptimizedAssets }; }); return analysis || this.getDefaultAssetAnalysis(); } catch (error) { return this.getDefaultAssetAnalysis(); } } async detectFlutterWebIssues() { if (!this.page) { return []; } try { const issues = await this.page.evaluate(() => { const detectedIssues = []; const userAgent = navigator.userAgent; // Check for browser-specific issues if (userAgent.includes('Safari')) { detectedIssues.push({ type: 'rendering', severity: 'warning', browser: 'Safari', description: 'Safari may have text rendering inconsistencies with CanvasKit', solution: 'Consider using HTML renderer for Safari users', codeExample: 'flutter build web --web-renderer html' }); detectedIssues.push({ type: 'performance', severity: 'warning', browser: 'Safari', description: 'Safari WebAssembly performance may be slower than other browsers', solution: 'Monitor performance metrics and consider HTML renderer fallback' }); } if (userAgent.includes('Firefox')) { detectedIssues.push({ type: 'performance', severity: 'info', browser: 'Firefox', description: 'Firefox may have slower CanvasKit rendering performance', solution: 'Test performance on Firefox and optimize accordingly' }); } // Check for mobile issues if (/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)) { detectedIssues.push({ type: 'gesture', severity: 'warning', description: 'Mobile gesture handling may conflict with browser gestures', solution: 'Test gesture interactions thoroughly on mobile devices', codeExample: 'Use GestureDetector with proper hit testing' }); detectedIssues.push({ type: 'performance', severity: 'warning', description: 'Mobile devices may have performance limitations', solution: 'Optimize for mobile performance and consider device-specific builds' }); } // Check for input issues const hasTextInput = document.querySelector('input, textarea, [contenteditable]'); if (hasTextInput) { detectedIssues.push({ type: 'input', severity: 'info', description: 'Text input handling may vary across browsers', solution: 'Test text input functionality across different browsers', codeExample: 'Use TextFormField with proper validation' }); } // Check for font loading issues const customFonts = []; try { if (document.fonts && typeof document.fonts.forEach === 'function') { document.fonts.forEach((font) => { if (!['Arial', 'Helvetica', 'Times', 'Courier'].includes(font.family)) { customFonts.push(font); } }); } } catch (error) { // Fallback if forEach method is not available } if (customFonts.length > 0) { detectedIssues.push({ type: 'font', severity: 'info', description: 'Custom fonts may cause layout shifts during loading', solution: 'Use font-display: swap and preload critical fonts', codeExample: 'Add font preloading to index.html' }); } return detectedIssues; }); return issues || []; } catch (error) { return []; } } async getFlutterHealthCheck() { if (!this.page) { return { overall: 'critical', checks: [], warnings: [], errors: ['No page attached'] }; } try { const healthCheck = await this.page.evaluate(() => { const checks = []; const warnings = []; const errors = []; // Check Flutter initialization const hasFlutter = !!window._flutter || !!window.flutter; checks.push({ category: 'initialization', status: hasFlutter ? 'pass' : 'fail', message: hasFlutter ? 'Flutter framework detected' : 'Flutter framework not detected' }); if (!hasFlutter) { errors.push('Flutter framework not properly initialized'); } // Check renderer const hasCanvasKit = !!window.CanvasKit; const hasHtmlRenderer = document.querySelector('flt-scene') !== null; const hasRenderer = hasCanvasKit || hasHtmlRenderer; checks.push({ category: 'renderer', status: hasRenderer ? 'pass' : 'fail', message: hasRenderer ? `Renderer: ${hasCanvasKit ? 'CanvasKit' : 'HTML'}` : 'No renderer detected' }); if (!hasRenderer) { errors.push('No Flutter renderer detected'); } // Check performance const performanceEntries = performance.getEntriesByType('navigation'); const loadTime = performanceEntries.length > 0 ? performanceEntries[0].loadEventEnd - performanceEntries[0].fetchStart : 0; checks.push({ category: 'performance', status: loadTime < 3000 ? 'pass' : loadTime < 5000 ? 'warning' : 'fail', message: `Load time: ${loadTime}ms` }); if (loadTime > 3000) { warnings.push(`Slow load time: ${loadTime}ms`); } // Check memory const memoryInfo = performance.memory; if (memoryInfo) { const memoryUsage = memoryInfo.usedJSHeapSize / 1024 / 1024; // MB checks.push({ category: 'memory', status: memoryUsage < 50 ? 'pass' : memoryUsage < 100 ? 'warning' : 'fail', message: `Memory usage: ${memoryUsage.toFixed(1)}MB` }); if (memoryUsage > 50) { warnings.push(`High memory usage: ${memoryUsage.toFixed(1)}MB`); } } // Check for errors const flutterDebug = window.__FLUTTER_DEBUG__; if (flutterDebug && flutterDebug.errors && flutterDebug.errors.length > 0) { errors.push(...flutterDebug.errors); } // Determine overall status const hasErrors = errors.length > 0 || checks.some(check => check.status === 'fail'); const hasWarnings = warnings.length > 0 || checks.some(check => check.status === 'warning'); const overall = hasErrors ? 'critical' : hasWarnings ? 'warning' : 'healthy'; return { overall, checks, warnings, errors }; }); return healthCheck || { overall: 'critical', checks: [], warnings: [], errors: ['Health check failed'] }; } catch (error) { return { overall: 'critical', checks: [], warnings: [], errors: ['Health check failed'] }; } } async setupPlatformChannelMonitoring() { if (!this.page) return; await this.page.evaluate(() => { const flutterDebug = window.__FLUTTER_DEBUG__; // Monitor platform channel messages const originalPostMessage = window.postMessage; window.postMessage = function (message, targetOriginOrOptions) { if (message && message.method && message.channel) { if (!flutterDebug.platformChannels.has(message.channel)) { flutterDebug.platformChannels.set(message.channel, { messageCount: 0, lastMessage: null, lastError: null }); } const channelInfo = flutterDebug.platformChannels.get(message.channel); channelInfo.messageCount++; channelInfo.lastMessage = message; } return originalPostMessage.call(this, message, targetOriginOrOptions); }; }); } async setupGestureTracking() { if (!this.page) return; await this.page.evaluate(() => { const flutterDebug = window.__FLUTTER_DEBUG__; // Track gesture conflicts const gestureEvents = ['touchstart', 'touchmove', 'touchend', 'click', 'scroll']; gestureEvents.forEach(eventType => { document.addEventListener(eventType, (event) => { // Check if event is in Flutter area const flutterArea = document.querySelector('flt-glass-pane'); if (flutterArea && flutterArea.contains(event.target)) { const conflict = { type: eventType, timestamp: Date.now(), target: event.target?.tagName || 'unknown', preventDefault: event.defaultPrevented }; flutterDebug.gestures.conflicts.push(conflict); // Keep only recent conflicts if (flutterDebug.gestures.conflicts.length > 100) { flutterDebug.gestures.conflicts.shift(); } } }, true); }); }); } getDefaultAssetAnalysis() { return { assets: [], fonts: [], totalAssets: 0, totalSize: 0, totalLoadTime: 0, unoptimizedAssets: 0 }; } } //# sourceMappingURL=flutter-platform-integration.js.map