const SECRET_KEYS = /^(authorization|cookie|set-cookie|x-api-key|api[-_]?key|token|access[-_]?token|refresh[-_]?token|session(id)?|csrf|x-csrf-token|password|secret|private[-_]?key)$/i; const SECRET_QUERY = /([?&](api_?key|token|key|secret|session|sig|signature|auth)=)[^&#]+/gi; /** Removes secrets from a URL query string. */ export function redactUrl(url: string): string { return url.replace(SECRET_QUERY, "$1[redacted]"); } /** Deep-copies an object removing secret-looking keys (headers, cookies, tokens). */ export function redactObject(value: T, depth = 0): T { if (depth > 12) return value; if (Array.isArray(value)) return value.map((v) => redactObject(v, depth + 1)) as T; if (value && typeof value === "object") { const out: Record = {}; for (const [k, v] of Object.entries(value as Record)) { out[k] = SECRET_KEYS.test(k) ? "[redacted]" : redactObject(v, depth + 1); } return out as T; } if (typeof value === "string" && value.length > 20 && /^(Bearer|Basic)\s/i.test(value)) return "[redacted]" as T; return value; }