mirror of
https://github.com/jo-inc/camofox-browser.git
synced 2026-10-02 04:14:41 +08:00
83 lines
4.9 KiB
JavaScript
83 lines
4.9 KiB
JavaScript
// HTTP request classification helpers -- kept separate from metrics.js
|
|
// Separated from server.js to keep HTTP method classification in its own module.
|
|
|
|
/**
|
|
* Derive a short action name from an Express request for metrics labeling.
|
|
*/
|
|
export function actionFromReq(req) {
|
|
const method = req.method;
|
|
const routePath = req.route?.path;
|
|
const path = routePath || req.path || '';
|
|
if (path === '/tabs' && method === 'POST') return 'create_tab';
|
|
if (path === '/tabs/:tabId' && method === 'DELETE') return 'delete_tab';
|
|
if (path === '/tabs/group/:listItemId' && method === 'DELETE') return 'delete_tab_group';
|
|
if (path === '/sessions/:userId' && method === 'DELETE') return 'delete_session';
|
|
if (path === '/sessions/:userId/cookies' && method === 'POST') return 'set_cookies';
|
|
if (path === '/tabs/open' && method === 'POST') return 'open_url';
|
|
if (path === '/tabs' && method === 'GET') return 'list_tabs';
|
|
|
|
const tabAction = path.match(/^\/tabs\/(?:[^/]+|:tabId)\/(\w+)$/);
|
|
if (tabAction) return tabAction[1];
|
|
|
|
if (path.match(/^\/tabs\/(?:[^/]+|:tabId)$/) && method === 'DELETE') return 'delete_tab';
|
|
if (path.match(/^\/tabs\/group\/(?:[^/]+|:listItemId)$/) && method === 'DELETE') return 'delete_tab_group';
|
|
if (path.match(/^\/sessions\/(?:[^/]+|:userId)$/) && method === 'DELETE') return 'delete_session';
|
|
if (path.match(/^\/sessions\/(?:[^/]+|:userId)\/cookies$/) && method === 'POST') return 'set_cookies';
|
|
|
|
// legacy compat routes
|
|
if (['/start', '/stop', '/navigate', '/snapshot', '/act'].includes(path)) return path.slice(1);
|
|
if (path === '/youtube/transcript') return 'youtube_transcript';
|
|
if (path === '/health') return 'health';
|
|
if (path === '/metrics') return 'metrics';
|
|
return `${method.toLowerCase()}_${path.replace(/[/:]/g, '_').replace(/_+/g, '_').replace(/^_|_$/g, '')}`;
|
|
}
|
|
|
|
/**
|
|
* Classify an error into a failure type string for metrics labeling.
|
|
*/
|
|
export function classifyError(err) {
|
|
if (!err) return 'unknown';
|
|
const msg = err.message || '';
|
|
|
|
if (err.code === 'stale_refs' || err.name === 'StaleRefsError') return 'stale_refs';
|
|
if (err.code === 'element_not_actionable') return 'element_error';
|
|
if (err.code === 'invalid_selector' ||
|
|
(msg.includes('Unexpected token') && msg.includes('selector')) ||
|
|
(msg.includes('Unsupported token') && msg.includes('selector')) ||
|
|
msg.includes('Malformed selector') || msg.includes('Invalid selector') ||
|
|
msg.includes('is not a valid selector')) return 'invalid_selector';
|
|
if (msg === 'Tab lock queue timeout') return 'tab_lock_timeout';
|
|
if (msg === 'Tab destroyed') return 'tab_destroyed';
|
|
if (msg.includes('Target page, context or browser has been closed') ||
|
|
msg.includes('browser has been closed') ||
|
|
msg.includes('Context closed') ||
|
|
msg.includes('Browser closed')) return 'dead_context';
|
|
if (msg.includes('timed out after') ||
|
|
(msg.includes('Timeout') && msg.includes('exceeded'))) return 'timeout';
|
|
if (msg.includes('Maximum concurrent sessions')) return 'session_limit';
|
|
if (msg.includes('Maximum tabs per session') || msg.includes('Maximum global tabs')) return 'tab_limit';
|
|
if (msg.includes('User concurrency limit reached') || msg.includes('concurrency limit reached')) return 'concurrency_timeout';
|
|
if (msg.includes('NS_ERROR_PROXY') || msg.includes('proxy connection') ||
|
|
msg.includes('Proxy connection')) return 'proxy';
|
|
if (msg.includes('Browser launch timeout') || msg.includes('Failed to launch')) return 'browser_launch';
|
|
if (msg.includes('strict mode violation') && msg.includes('resolved to')) return 'ambiguous_selector';
|
|
if (msg.includes('intercepts pointer events')) return 'element_error';
|
|
if (msg.includes('not visible') || msg.includes('Malformed value') || msg.includes('not an <input>') ||
|
|
msg.includes('Input of type "submit" cannot be filled') || msg.includes('is not fillable') ||
|
|
msg.includes('element is not attached') || msg.includes('Element is not attached') ||
|
|
msg.includes('no bounding box')) return 'element_error';
|
|
if (msg.includes('Blocked URL scheme') || msg.includes('Invalid URL')) return 'invalid_url';
|
|
if (msg.includes('Navigation aborted: tab deleted')) return 'tab_destroyed';
|
|
if (msg.includes('Execution context was destroyed') ||
|
|
msg.includes('Cannot find context with specified id') ||
|
|
msg.includes('Frame was detached') ||
|
|
msg.includes('Navigation interrupted') ||
|
|
msg.includes('NS_ERROR_NET_INTERRUPT') ||
|
|
msg.includes('NS_BINDING_ABORTED')) return 'navigation_race';
|
|
if (msg.includes('NS_ERROR_ABORT')) return 'nav_aborted';
|
|
if (msg.includes('Page crashed') || msg.includes('Target crashed') || msg.includes('crashed page')) return 'page_crashed';
|
|
if (msg.includes('Navigation failed') || msg.includes('ERR_ABORTED')) return 'nav_aborted';
|
|
if (msg.includes('net::') || msg.includes('ERR_NAME') || msg.includes('ERR_CONNECTION')) return 'network';
|
|
return 'unknown';
|
|
}
|