export function cleanText(value) { return String(value ?? "").trim(); } export function isTruthy(value) { return value === true || value === "true" || value === "1" || value === 1 || value === "on" || value === "yes"; } export function escapeHtml(value) { return String(value ?? "") .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } export function escapeAttr(value) { return escapeHtml(value).replace(/`/g, "`"); } export function formatDateTime(value) { if (!value) return ""; const date = new Date(value); if (Number.isNaN(date.getTime())) return escapeHtml(value); const yyyy = date.getFullYear(); const mm = String(date.getMonth() + 1).padStart(2, "0"); const dd = String(date.getDate()).padStart(2, "0"); const hh = String(date.getHours()).padStart(2, "0"); const mi = String(date.getMinutes()).padStart(2, "0"); return `${yyyy}-${mm}-${dd} ${hh}:${mi}`; } export function stripMarkdown(text) { return String(text ?? "") .replace(/```[\s\S]*?```/g, " ") .replace(/\$\$[\s\S]*?\$\$/g, " ") .replace(/\$[^$\n]+\$/g, " ") .replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1") .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") .replace(/^\s{0,3}#{1,6}\s+/gm, "") .replace(/^\s{0,3}>\s?/gm, "") .replace(/^\s{0,3}[-*+]\s+/gm, "") .replace(/^\s{0,3}\d+[.)]\s+/gm, "") .replace(/[*_`~#]/g, " ") .replace(/\s+/g, " ") .trim(); } export function b64EncodeUtf8(str) { return btoa(unescape(encodeURIComponent(str))); }