import { canonicalizeRoute } from './route-normalize.mjs'; const KIND_LABELS = new Map([ ['slow_route', 'Slow route'], ['uncached_route', 'Low cache-hit route'], ['cold_start', 'Cold starts'], ['route_errors', 'Route errors'], ['cache_header_gap', 'Missing cache headers'], ['image_optimization', 'Image optimization'], ['external_api_slow', 'Slow external API'], ['isr_overrevalidation', 'ISR over-revalidation'], ['middleware_heavy', 'Heavy middleware'], ['cwv_poor', 'Poor Core Web Vitals'], ['platform_fluid_compute', 'Fluid Compute usage'], ['platform_bot_protection', 'Bot traffic'], ['rendering_candidate', 'Rendering opportunity'], ['missing_cache_headers', 'Missing cache headers'], ['max_age_without_s_maxage', 'Browser-only cache header'], ['force_dynamic', 'Forced dynamic rendering'], ['headers_in_page', 'Dynamic API in page'], ['unoptimized_image', 'Image optimization gap'], ['large_static_asset', 'Large static asset'], ['source_maps_production', 'Production source maps'], ['edge_heavy_import', 'Heavy Edge import'], ]); const SIGNAL_LABELS = new Map([ ['inv', 'function invocations'], ['runs', 'function invocations'], ['middleware_inv', 'middleware invocations'], ['total_req', 'total requests'], ['requests', 'requests'], ['p95', '95th percentile duration'], ['p75', '75th percentile duration'], ['5xx', '5xx error rate'], ['errs', '5xx errors'], ['rate', '5xx error rate'], ['cache', 'cache hit rate'], ['get', 'GET request share'], ['cold', 'cold start rate'], ['writes', 'ISR write units'], ['reads', 'ISR read units'], ['w/r', 'ISR writes per read'], ['ratio', 'ratio'], ['host', 'host'], ['calls', 'external API calls'], ['edge_cost', 'Edge Request cost units'], ['bot_protection', 'Bot Protection'], ['bot_fdt_pct', 'bot Fast Data Transfer share'], ['LCP', 'Largest Contentful Paint (LCP)'], ['INP', 'Interaction to Next Paint (INP)'], ['CLS', 'Cumulative Layout Shift (CLS)'], ]); const REQUEST_COUNT_KINDS = new Set([ 'uncached_route', ]); const PUBLIC_ASSIGNMENT_LABELS = new Map([ ...SIGNAL_LABELS, ['deepDive.latency.p95', 'deepDive latency p95'], ['deepDive.cpu.p95', 'deepDive CPU p95'], ['deepDive.ttfb.p95', 'deepDive TTFB p95'], ['cpu.p95', 'CPU p95'], ['latency.p95', 'latency p95'], ['ttfb.p95', 'TTFB p95'], ['cache_result', 'cache result'], ['http_status', 'HTTP status'], ['error_code', 'error code'], ['status', 'status'], ['count', 'count'], ]); export function formatKind(kind) { if (!kind) return 'Candidate'; if (KIND_LABELS.has(kind)) return KIND_LABELS.get(kind); return String(kind) .split(/[_-]+/g) .filter(Boolean) .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join(' ') || 'Candidate'; } export function formatRoute(candidate) { const route = candidate?.displayRoute ?? candidate?.route ?? candidate?.hostname ?? null; if (route) return String(canonicalizeRoute(route)); if (Array.isArray(candidate?.files) && candidate.files.length > 0) return candidate.files[0]; return 'account-wide'; } export function formatSignal(signal, context = {}) { if (typeof signal !== 'string' || signal.trim() === '') return 'no signal recorded'; const parts = signal .split(',') .map((part) => part.trim()) .filter(Boolean) .map((part) => formatSignalPart(part, context)); return parts.length > 0 ? parts.join('; ') : signal; } export function formatPublicText(value) { if (value == null) return ''; return normalizeObservedWindowUnits(String(value)) .replace(/\bo11y\b/gi, 'observability') .replace(/\bcache[- ]components gotcha\b/gi, 'Cache Components edge case') .replace(/\bcache_result\b(?!\s*=)/g, 'cache result') .replace(/\bhttp_status\b(?!\s*=)/g, 'HTTP status') .replace(/\berror_code\b(?!\s*=)/g, 'error code') .replace(/,(?=\s*([A-Za-z0-9][\w./-]*)=)/g, (match, key) => PUBLIC_ASSIGNMENT_LABELS.has(key) ? '; ' : match ) .replace(/\b([A-Za-z0-9][\w./-]*)=([^,;\s]+)/g, (match, key, rawValue) => { const label = PUBLIC_ASSIGNMENT_LABELS.get(key); if (!label) return match; return `${label}: ${formatSignalValue(key, rawValue)}`; }) .replace(/\b(cache breakdown[^.!?\n;]{0,160}?)\b(?:function\s+)?invocations\b/gi, (match, prefix) => /\bstatus distribution\b/i.test(prefix) ? match : `${prefix}requests` ) .replace(/\b(cache breakdown[^.!?\n;]{0,220}?\bout of\s+[\d,]+)\s+invocations\b/gi, '$1 requests') .replace(/\b(cache hits over\s+[\d,.]+(?:\s?(?:K|M|B))?)\s+invocations\b/gi, '$1 requests') .replace(/\b(?:function\s+)?invocations\b([^.!?\n;]{0,120}\b(?:empty\s+)?cache result(?: label)?\b)/gi, 'requests$1'); } export function normalizeObservedWindowUnits(value) { if (value == null) return ''; return String(value) .replace(/(?