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
252 lines • 9.16 kB
JavaScript
/**
* NetworkCoordinator - Consolidates network request/response debugging functionality
*
* Provides unified interface for:
* - Network request interception and monitoring
* - Response capture and analysis
* - Performance metrics tracking
* - Error detection and reporting
* - Network debugging report generation
*/
export class NetworkCoordinator {
isMonitoring = false;
capturedRequests = [];
capturedResponses = [];
networkErrors = [];
requestTimings = new Map();
currentPage;
routeHandler;
responseHandler;
constructor() {
this.routeHandler = this.handleRequest.bind(this);
this.responseHandler = this.handleResponse.bind(this);
}
/**
* Setup network monitoring on the given page
*/
async setupNetworkMonitoring(page) {
if (this.isMonitoring) {
return; // Already monitoring
}
try {
this.currentPage = page;
// Intercept all network requests
await page.route('**/*', this.routeHandler);
// Listen for responses
page.context().on('response', this.responseHandler);
this.isMonitoring = true;
}
catch (error) {
throw new Error(`Failed to setup network monitoring: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Handle intercepted network requests
*/
async handleRequest(route, request) {
try {
const requestId = this.generateRequestId();
// Capture request details
const networkRequest = {
requestId,
url: request.url(),
method: request.method(),
headers: request.headers(),
postData: request.postData(),
timestamp: Date.now(),
frameUrl: request.frame()?.url(),
};
this.capturedRequests.push(networkRequest);
this.requestTimings.set(requestId, Date.now());
// Continue with the request
await route.continue();
}
catch (error) {
// Handle connection errors
this.networkErrors.push({
type: 'connection_error',
url: route.request().url(),
message: error instanceof Error ? error.message : 'Connection failed',
timestamp: Date.now(),
});
}
}
/**
* Handle network responses
*/
async handleResponse(response) {
try {
const requestId = this.findRequestId(response.url());
const responseTime = Date.now();
const requestTime = this.requestTimings.get(requestId || '') || responseTime;
let bodySize = 0;
try {
const body = await response.body();
bodySize = body.length;
}
catch (error) {
// Body read failed, continue without size
}
const networkResponse = {
requestId: requestId || this.generateRequestId(),
url: response.url(),
status: response.status(),
statusText: response.statusText(),
headers: response.headers(),
bodySize,
responseTime: responseTime - requestTime,
timestamp: responseTime,
};
this.capturedResponses.push(networkResponse);
// Check for HTTP errors
if (response.status() >= 400) {
this.networkErrors.push({
type: 'http_error',
url: response.url(),
status: response.status(),
statusText: response.statusText(),
message: `HTTP ${response.status()}: ${response.statusText()}`,
timestamp: responseTime,
requestId,
});
}
}
catch (error) {
// Handle response processing errors gracefully
console.warn('NetworkCoordinator: Response processing error:', error);
}
}
/**
* Get captured network requests
*/
getCapturedRequests() {
return [...this.capturedRequests];
}
/**
* Get API requests (alias for getCapturedRequests for consistency with LocalDebugEngine)
* Returns requests in the legacy format expected by ReactStateCoordinator
*/
getApiRequests() {
// Convert NetworkCoordinator format to LocalDebugEngine format
const requests = this.getCapturedRequests();
const responses = this.getCapturedResponses();
return requests.map(request => {
const response = responses.find(r => r.requestId === request.requestId);
return {
url: request.url,
method: request.method,
headers: request.headers,
timestamp: new Date(request.timestamp),
status: response ? 'complete' : 'pending',
responseStatus: response?.status,
responseStatusText: response?.statusText,
responseHeaders: response?.headers,
requestBody: request.postData,
responseBody: response?.responseBody,
responseSize: response?.bodySize,
duration: response ? response.responseTime : undefined,
resourceType: undefined,
queryParams: undefined
};
});
}
/**
* Get captured network responses
*/
getCapturedResponses() {
return [...this.capturedResponses];
}
/**
* Get detected network errors
*/
getNetworkErrors() {
return [...this.networkErrors];
}
/**
* Get network performance metrics
*/
getNetworkMetrics() {
const totalRequests = this.capturedRequests.length;
const successfulRequests = this.capturedResponses.filter(r => r.status < 400).length;
const failedRequests = this.capturedResponses.filter(r => r.status >= 400).length;
const responseTimes = this.capturedResponses.map(r => r.responseTime);
const averageResponseTime = responseTimes.length > 0
? responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length
: 0;
const totalDataTransferred = this.capturedResponses.reduce((sum, r) => sum + r.bodySize, 0);
return {
totalRequests,
successfulRequests,
failedRequests,
averageResponseTime,
totalDataTransferred,
};
}
/**
* Generate comprehensive network debugging report
*/
generateNetworkReport() {
const metrics = this.getNetworkMetrics();
const insights = [];
// Generate performance insights
if (metrics.averageResponseTime > 2000) {
insights.push('High average response time detected (>2s) - consider optimizing API calls');
}
if (metrics.failedRequests > 0) {
insights.push(`${metrics.failedRequests} failed requests detected - check error responses`);
}
if (metrics.totalDataTransferred > 1024 * 1024) {
insights.push(`Large data transfer detected (${Math.round(metrics.totalDataTransferred / 1024 / 1024)}MB) - consider response compression`);
}
const summary = `Network Activity Summary:
- Total Requests: ${metrics.totalRequests}
- Successful: ${metrics.successfulRequests}
- Failed: ${metrics.failedRequests}
- Average Response Time: ${Math.round(metrics.averageResponseTime)}ms
- Data Transferred: ${Math.round(metrics.totalDataTransferred / 1024)}KB`;
return {
metrics,
requests: this.getCapturedRequests(),
responses: this.getCapturedResponses(),
errors: this.getNetworkErrors(),
summary,
insights,
};
}
/**
* Cleanup network monitoring and reset state
*/
cleanup() {
if (this.currentPage && this.isMonitoring) {
try {
this.currentPage.unroute('**/*');
this.currentPage.context().off('response', this.responseHandler);
}
catch (error) {
// Cleanup errors are non-fatal
console.warn('NetworkCoordinator: Cleanup warning:', error);
}
}
// Reset state
this.isMonitoring = false;
this.capturedRequests = [];
this.capturedResponses = [];
this.networkErrors = [];
this.requestTimings.clear();
this.currentPage = undefined;
}
/**
* Generate unique request ID
*/
generateRequestId() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* Find request ID by URL (best effort matching)
*/
findRequestId(url) {
const request = this.capturedRequests.find(req => req.url === url);
return request?.requestId;
}
}
//# sourceMappingURL=network-coordinator.js.map