// Centralized text-to-HTML escaping. Use everywhere user-provided strings flow
// into an HTML context (emails, raw markup, etc). React's JSX rendering escapes
// by default; this is for the non-JSX paths.
const REPLACE: Record = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
};
export function escapeHtml(input: unknown): string {
if (input === null || input === undefined) return "";
return String(input).replace(/[&<>"']/g, (c) => REPLACE[c] ?? c);
}
// Strip everything that smells like markup. Use for places where the value
// should be plain text but might be rendered raw (mailer subject lines, etc.).
export function stripTags(input: unknown): string {
return String(input ?? "").replace(/<[^>]*>/g, "");
}
// Quick allowlist URL check — refuses anything that isn't http/https. Used on
// the redirect-after-submit setting and on webhook URLs.
export function isSafeUrl(url: string): boolean {
try {
const u = new URL(url);
return u.protocol === "http:" || u.protocol === "https:";
} catch {
return false;
}
}