spb/autoscholar
Public
1import "server-only";2import { marked } from "marked";3import sanitizeHtml from "sanitize-html";45const ALLOWED = {6 allowedTags: [7 "h1",8 "h2",9 "h3",10 "h4",11 "h5",12 "h6",13 "p",14 "br",15 "hr",16 "ul",17 "ol",18 "li",19 "blockquote",20 "pre",21 "code",22 "em",23 "strong",24 "del",25 "a",26 "table",27 "thead",28 "tbody",29 "tr",30 "th",31 "td",32 "sup",33 "sub",34 "span",35 ],36 allowedAttributes: {37 a: ["href", "title", "rel"],38 code: ["class"],39 span: ["class"],40 th: ["align"],41 td: ["align"],42 },43 allowedSchemes: ["http", "https", "mailto"],44 allowProtocolRelative: false,45 transformTags: { a: sanitizeHtml.simpleTransform("a", { rel: "nofollow noopener noreferrer" }) },46 disallowedTagsMode: "discard" as const,47};4849/** Markdown → sanitized HTML with a strict allowlist (no images, no scripts, no raw HTML passthrough). */50export function renderMarkdown(md: string): string {51 const html = marked.parse(md, { async: false, gfm: true, breaks: false }) as string;52 return sanitizeHtml(html, ALLOWED);53}54