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
JavaScript
/**
* 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