export const CREDENTIAL_KEY = /(?:token|secret|password|api[ _-]?key|authorization|cookie|private[ _-]?key)/i;
const MAX_REDACTION_DEPTH = 32;

const CREDENTIAL_ASSIGNMENT = new RegExp(
  `("?)(${CREDENTIAL_KEY.source})("?\\s*[:=]\\s*)("[^"]*"|'[^']*'|[^\\s,}\\]]+)`,
  "gi",
);

/**
 * Text-level counterpart for input that failed to parse, so no key/value tree exists
 * to walk. Masks the value of any credential-named assignment.
 */
export function redactBrowserText(value: string): string {
  return value.replace(CREDENTIAL_ASSIGNMENT, "$1$2$3[REDACTED]");
}

/** Replaces credential-named values with `[REDACTED]`, bounded against cyclic input. */
export function redactBrowserValue(value: unknown, depth = 0): unknown {
  if (depth >= MAX_REDACTION_DEPTH) return "[REDACTED]";
  if (Array.isArray(value)) return value.map((entry) => redactBrowserValue(entry, depth + 1));
  if (!value || typeof value !== "object") return value;
  return Object.fromEntries(Object.entries(value).map(([key, nested]) => [
    key, CREDENTIAL_KEY.test(key) ? "[REDACTED]" : redactBrowserValue(nested, depth + 1),
  ]));
}
