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

237 lines â€ĸ 10.1 kB
/** * Browser Permission Handler * Framework-agnostic module for handling browser permissions */ export class BrowserPermissionHandler { static DEFAULT_PERMISSIONS = [ 'geolocation', 'notifications', 'camera', 'microphone', 'clipboard-read', 'clipboard-write' ]; static DEFAULT_LOCATION = { latitude: 47.6062, // Seattle, WA longitude: -122.3321, accuracy: 10 }; /** * Configure permissions for a browser context or page */ static async configurePermissions(pageOrContext, options) { const permissions = options?.permissions || this.DEFAULT_PERMISSIONS; const geolocation = options?.geolocation || this.DEFAULT_LOCATION; const autoAccept = options?.autoAcceptDialogs !== false; // Get context (works for both page and context) const context = 'context' in pageOrContext ? pageOrContext.context() : pageOrContext; const page = 'context' in pageOrContext ? pageOrContext : null; // Grant permissions at context level try { await context.grantPermissions(permissions); // console.log(`✅ Permissions pre-granted: ${permissions.join(', ')}`); } catch (e) { // console.log('âš ī¸ Could not pre-grant permissions:', e instanceof Error ? e.message : String(e)); } // Set geolocation at context level try { await context.setGeolocation(geolocation); // console.log(`📍 Default location set: ${geolocation.latitude}, ${geolocation.longitude}`); } catch (e) { // console.log('âš ī¸ Could not set default location:', e instanceof Error ? e.message : String(e)); } // If we have a page, add additional handlers if (page) { // Inject permission mocking script await this.injectPermissionMocks(page, geolocation); // Set up dialog handler if auto-accept is enabled if (autoAccept) { this.setupDialogHandler(page); } } } /** * Inject permission mocking scripts into the page */ static async injectPermissionMocks(page, geolocation) { await page.addInitScript((geo) => { // Track all permission requests window.permissionRequests = []; // Mock Permissions API if ('permissions' in navigator) { const originalQuery = navigator.permissions.query; navigator.permissions.query = async function (descriptor) { // console.log('🔐 Permission query:', descriptor); window.permissionRequests.push({ type: 'permission-query', name: descriptor.name, timestamp: Date.now() }); // Auto-grant common permissions const autoGrantPermissions = [ 'geolocation', 'notifications', 'camera', 'microphone', 'clipboard-read', 'clipboard-write' ]; if (autoGrantPermissions.includes(descriptor.name)) { return { state: 'granted', addEventListener: () => { }, removeEventListener: () => { }, onchange: null }; // Cast to any to satisfy TypeScript } return originalQuery.call(this, descriptor); }; } // Mock Geolocation API const mockPosition = { coords: { latitude: geo.latitude, longitude: geo.longitude, accuracy: geo.accuracy || 10, altitude: null, altitudeAccuracy: null, heading: null, speed: null }, timestamp: Date.now() }; // Override getCurrentPosition const originalGetCurrentPosition = navigator.geolocation.getCurrentPosition; navigator.geolocation.getCurrentPosition = function (success, error, options) { // console.log('📍 Geolocation requested (getCurrentPosition)'); window.permissionRequests.push({ type: 'geolocation', method: 'getCurrentPosition', timestamp: Date.now() }); // Always succeed with mock location setTimeout(() => { // console.log('📍 Returning mock position:', mockPosition.coords); success(mockPosition); }, 100); }; // Override watchPosition const originalWatchPosition = navigator.geolocation.watchPosition; navigator.geolocation.watchPosition = function (success, error, options) { // console.log('📍 Geolocation requested (watchPosition)'); window.permissionRequests.push({ type: 'geolocation', method: 'watchPosition', timestamp: Date.now() }); // Return mock position updates const watchId = setInterval(() => { mockPosition.timestamp = Date.now(); success(mockPosition); }, 1000); return watchId; }; // Override clearWatch const originalClearWatch = navigator.geolocation.clearWatch; navigator.geolocation.clearWatch = function (watchId) { // console.log('📍 Clearing geolocation watch:', watchId); clearInterval(watchId); originalClearWatch.call(this, watchId); }; // Mock Notification API if ('Notification' in window) { const originalRequestPermission = Notification.requestPermission; Notification.requestPermission = async function () { // console.log('🔔 Notification permission requested'); window.permissionRequests.push({ type: 'notification', method: 'requestPermission', timestamp: Date.now() }); return 'granted'; }; // Override permission property Object.defineProperty(Notification, 'permission', { get: () => 'granted' }); } // Mock MediaDevices API if ('mediaDevices' in navigator) { const originalGetUserMedia = navigator.mediaDevices.getUserMedia; navigator.mediaDevices.getUserMedia = async function (constraints) { // console.log('📹 Media device access requested:', constraints); window.permissionRequests.push({ type: 'media', method: 'getUserMedia', timestamp: Date.now() }); // Create mock media stream const canvas = document.createElement('canvas'); canvas.width = 640; canvas.height = 480; const ctx = canvas.getContext('2d'); if (ctx) { ctx.fillStyle = 'green'; ctx.fillRect(0, 0, 640, 480); } const stream = canvas.captureStream(30); return stream; }; } }, geolocation); } /** * Set up dialog handler for permission prompts */ static setupDialogHandler(page) { page.on('dialog', async (dialog) => { const message = dialog.message().toLowerCase(); // console.log(`🔔 Dialog detected: ${dialog.type()} - ${dialog.message()}`); // Check if it's a permission-related dialog const permissionKeywords = [ 'location', 'geolocation', 'permission', 'allow', 'camera', 'microphone', 'notification', 'clipboard' ]; const isPermissionDialog = permissionKeywords.some(keyword => message.includes(keyword)); if (isPermissionDialog) { // console.log('✅ Auto-accepting permission dialog'); await dialog.accept(); } else { // console.log('â„šī¸ Dialog not recognized as permission request'); // You might want to handle other dialogs differently } }); } /** * Get all permission requests made during the session */ static async getPermissionRequests(page) { try { const requests = await page.evaluate(() => window.permissionRequests || []); return requests; } catch { return []; } } /** * Check if a specific permission was requested */ static async wasPermissionRequested(page, permissionType) { const requests = await this.getPermissionRequests(page); return requests.some(req => req.type === permissionType || req.name === permissionType); } /** * Wait for a permission request */ static async waitForPermissionRequest(page, permissionType, timeout = 5000) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { const requested = await this.wasPermissionRequested(page, permissionType); if (requested) return true; await page.waitForTimeout(100); } return false; } } //# sourceMappingURL=browser-permission-handler.js.map