UNPKG

magnitude-test

Version:

A TypeScript client for running automated UI tests through the Magnitude testing platform

199 lines (198 loc) 6.41 kB
const IPV4_IN_IPV6_PREFIX = '::f{4}:'; const LOOPBACK_IP_RANGES = [ // 127.0.0.0 - 127.255.255.255 (IPv4 loopback) new RegExp(`^(${IPV4_IN_IPV6_PREFIX})?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}`), // ::1 (IPv6 loopback) /^::1$/ ]; const PRIVATE_IP_RANGES = [ // 10.0.0.0 - 10.255.255.255 new RegExp(`^(${IPV4_IN_IPV6_PREFIX})?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}`), // 169.254.1.0 - 169.254.254.255 new RegExp(`^(${IPV4_IN_IPV6_PREFIX})?169\\.254\\.([1-9]|1?\\d\\d|2[0-4]\\d|25[0-4])\\.\\d{1,3}`), // 172.16.0.0 - 172.31.255.255 new RegExp(`^(${IPV4_IN_IPV6_PREFIX})?(172\\.1[6-9]|172\\.2\\d|172\\.3[0-1])\\.\\d{1,3}\\.\\d{1,3}`), // 192.168.0.0 - 192.168.255.255 new RegExp(`^(${IPV4_IN_IPV6_PREFIX})?192\\.168\\.\\d{1,3}\\.\\d{1,3}`), // fc00::/7 - Unique local addresses /^f[c-d][0-9a-f]{2}(::1$|:[0-9a-f]{1,4}){1,7}/, // fe80::/10 - Link-local addresses /^fe[89ab][0-9a-f](::1$|:[0-9a-f]{1,4}){1,7}/, // Include loopback ranges in private ranges ...LOOPBACK_IP_RANGES ]; const SPECIAL_LOCAL_IPS = ['::1', '::', '0.0.0.0']; const LOCALHOST_DOMAINS = ['localhost']; export function isLoopbackIp(address) { return (SPECIAL_LOCAL_IPS.includes(address) || LOOPBACK_IP_RANGES.some(pattern => pattern.test(address))); } export function isPrivateIp(address) { return (SPECIAL_LOCAL_IPS.includes(address) || PRIVATE_IP_RANGES.some(pattern => pattern.test(address))); } export function extractHostname(urlOrHostname) { try { if (!urlOrHostname.includes('://')) { urlOrHostname = 'http://' + urlOrHostname; } const parsedUrl = new URL(urlOrHostname); return parsedUrl.hostname.toLowerCase(); } catch (error) { return urlOrHostname.toLowerCase(); } } export function cleanHostname(hostname) { return hostname.replace(/^\[|\]$/g, ''); } export function isLocalhostDomain(hostname) { const lowerHostname = hostname.toLowerCase(); return (LOCALHOST_DOMAINS.includes(lowerHostname) || lowerHostname.endsWith('.localhost')); } export function isLoopbackHost(urlOrHostname) { try { const hostname = extractHostname(urlOrHostname); if (isLocalhostDomain(hostname)) { return true; } return isLoopbackIp(cleanHostname(hostname)); } catch (error) { console.error('Invalid URL or hostname:', error); return false; } } export function isPrivateHost(urlOrHostname) { try { const hostname = extractHostname(urlOrHostname); if (isLocalhostDomain(hostname)) { return true; } return isPrivateIp(cleanHostname(hostname)); } catch (error) { console.error('Invalid URL or hostname:', error); return false; } } export function isPrivateUrl(url) { return isPrivateHost(url); } export function isLoopbackUrl(url) { return isLoopbackHost(url); } export function addProtocolIfMissing(url) { if (!url.includes('://')) { if (isLoopbackUrl(url)) { // If local, assume HTTP return `http://${url}`; } else { // Otherwise assume HTTPS return `https://${url}`; } } else { return url; } } // export function tryDeriveEnvironmentPlannerClient(): PlannerClient | null { // // Order by approximate model suitability as planner // // Best: Gemini 2.5 pro // if (process.env.GOOGLE_API_KEY) { // // Google AI Studio // return { // 'provider': 'google-ai', // 'options': { // model: 'gemini-2.5-pro-preview-03-25', // apiKey: process.env.GOOGLE_API_KEY // } // } // } // // Patching out until vertex AI authorization issues are resolved // // if (process.env.GOOGLE_APPLICATION_CREDENTIALS) { // // // Google Vertex AI // // return { // // 'provider': 'vertex-ai', // // 'options': { // // location: 'us-central1', // // model: 'gemini-2.5-pro-preview-03-25' // // } // // } // // } // if (process.env.OPENROUTER_API_KEY) { // return { // 'provider': 'openai-generic', // 'options': { // baseUrl: "https://openrouter.ai/api/v1", // model: 'google/gemini-2.5-pro-preview-03-25', // apiKey: process.env.OPENROUTER_API_KEY // } // } // } // // Good // if (process.env.ANTHROPIC_API_KEY) { // return { // 'provider': 'anthropic', // 'options': { // model: 'claude-3-7-sonnet-latest', // apiKey: process.env.ANTHROPIC_API_KEY // } // } // } // // Ok // if (process.env.OPENAI_API_KEY) { // return { // 'provider': 'openai', // 'options': { // model: 'gpt-4.1-2025-04-14', // apiKey: process.env.OPENAI_API_KEY // } // } // } // return null; // } export function describeModel(client) { if (client.model !== 'unknown') { return `${client.provider}:${client.model}`; } else { return `${client.provider}`; } } // model name substrings with well known input/output cost that we can show export const knownCostMap = { 'gemini-2.5-pro': [1.25, 10.0], 'gemini-2.5-flash': [0.15, 0.60], 'claude-3.5-sonnet': [3.00, 15.00], 'claude-3.7-sonnet': [3.00, 15.00], 'gpt-4.1': [2.00, 8.00], 'gpt-4.1-mini': [0.40, 1.60], 'gpt-4.1-nano': [0.10, 0.40], 'gpt-4o': [3.75, 15.00], }; export function processUrl(...urls) { if (urls.length === 0) return; if (urls.length === 1) return urls[0]; const [base, relative, ...rest] = urls; if (!relative) return processUrl(base, ...rest); if (!base) return processUrl(relative, ...rest); try { return processUrl(new URL(relative).toString(), ...rest); // It's a full URL by itself } catch { try { // Not a full URL on its own, try to combine with base return processUrl(new URL(relative, base).toString(), ...rest); } catch (_e) { return processUrl(relative, ...rest); } } }