export type RssItem = { id: string; content: string; link: string; publishedAt: string | null }; const decode = (value: string) => value.replace(//g, "$1").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&"); const field = (xml: string, name: string) => decode(xml.match(new RegExp(`<${name}[^>]*>([\\s\\S]*?)`, "i"))?.[1]?.trim() || ""); export async function fetchRss(url: string) { const response = await fetch(url, { signal: AbortSignal.timeout(15_000), headers: { Accept: "application/rss+xml, application/xml, text/xml" } }); if (!response.ok) throw new Error(`RSS ${response.status}`); const xml = await response.text(); const entries = xml.match(//gi) || []; return entries.map((item) => { const link = field(item, "link"); const id = field(item, "guid") || link; return { id, link, content: field(item, "description") || field(item, "title"), publishedAt: field(item, "pubDate") ? new Date(field(item, "pubDate")).toISOString() : null }; }).filter((item) => item.id && item.content) as RssItem[]; }