/** Browser / WebView fetch failures are usually TypeError with an opaque message. */ export const AI_NETWORK_ERROR_CODE = "AI_UNREACHABLE"; const NETWORK_FETCH_HINTS = [ "failed to fetch", "networkerror", "network request failed", "load failed", "internet connection appears to be offline", ]; export function isLikelyNetworkFetchError(error: unknown): boolean { const name = error instanceof Error ? error.name : ""; const msg = (error instanceof Error ? error.message : String(error ?? "")).toLowerCase(); if (msg === AI_NETWORK_ERROR_CODE.toLowerCase()) return true; if (NETWORK_FETCH_HINTS.some((hint) => msg.includes(hint))) return true; // Some WebViews surface a bare TypeError when fetch cannot complete. return name === "TypeError" && !msg; } export function formatNetworkAwareMessage( template: string, error: unknown, networkCopy: string, ): string { const raw = error instanceof Error ? error.message : String(error ?? ""); const message = isLikelyNetworkFetchError(error) || isLikelyNetworkFetchError(raw) ? networkCopy : raw; if (template.includes("{message}")) { return template.split("{message}").join(String(message)); } return isLikelyNetworkFetchError(error) || isLikelyNetworkFetchError(raw) ? networkCopy : template; }