// Strips operator-internal implementation detail from error messages // before they're surfaced to public clients (Recap app, Recaps cloud, // any other SDK consumer). The relay's hardware backend wraps // Spark Control delegate names + internal IPs + wire-level details // into its thrown errors, which is great for the operator's relay // logs and audit table but those tokens shouldn't leak to whoever's // summarizing a YouTube link. // // Applies a two-stage scrub: // 1. Token replacement — known operator-private terms swap for // generic equivalents ("Parakeet" → "the transcribe service", // "Spark Control" → "the operator hardware", etc.). Stays // grammatical and still readable. // 2. Network-detail redaction — local IPs and internal URLs // collapse to "(internal)" so a client never sees an operator's // LAN topology. Public hostnames + Gemini's googleapis.com URLs // stay intact (they're not operator-private). // // The ORIGINAL message stays available in the relay's recordCall // audit row + console logs — only the client-facing surface gets // sanitized. const TOKEN_MAP = [ // Spark Control + its delegates [/Spark Control/gi, "the operator hardware"], [/spark-control(?:'s)?/gi, "the operator hardware"], [/sparkcontrol/gi, "the operator hardware"], // Parakeet (NVIDIA STT model wrapper) [/Parakeet/gi, "the transcribe service"], [/parakeet/gi, "the transcribe service"], // vLLM / Gemma / other LLM runners on operator hardware [/\bvLLM\b/gi, "the analyze service"], [/\bvllm\b/gi, "the analyze service"], [/\bGemma\b/g, "the analyze service"], // Diarization stack [/Sortformer/gi, "the diarization service"], [/TitaNet/gi, "the diarization service"], ]; // Match an IPv4 address — local-network (192.168/16, 10/8, 172.16-31) // and 127/8 (loopback). We don't redact public IPv4s in case a // public-facing error genuinely references one (rare for the relay // but possible). const PRIVATE_IP_RE = /\b(?:192\.168|10|172\.(?:1[6-9]|2\d|3[01])|127)\.\d{1,3}\.\d{1,3}(?::\d+)?/g; // Match an http(s) URL whose host is a private IP OR is *.local. // Both are operator-LAN-only. Public hostnames stay readable so a // Gemini-side error referencing generativelanguage.googleapis.com // keeps its diagnostic value. const PRIVATE_URL_RE = /https?:\/\/(?:(?:192\.168|10|172\.(?:1[6-9]|2\d|3[01])|127)\.\d{1,3}\.\d{1,3}(?::\d+)?|[A-Za-z0-9-]+\.local(?::\d+)?)[^\s)'"]*/g; export function sanitizeErrorForClient(input) { if (input == null) return ""; let s = typeof input === "string" ? input : (input.message || String(input)); // URL-shaped private hosts go first so the IP regex doesn't chew up // half of the URL before the full URL pattern fires. s = s.replace(PRIVATE_URL_RE, "(internal)"); s = s.replace(PRIVATE_IP_RE, "(internal)"); for (const [pattern, replacement] of TOKEN_MAP) { s = s.replace(pattern, replacement); } // Collapse any double-spaces created by the substitutions. s = s.replace(/\s{2,}/g, " ").trim(); return s; }