src/pages/now/rss.xml.ts 2.3 K raw
1
import rss from "@astrojs/rss";
2
import sanitizeHtml from "sanitize-html";
3
import MarkdownIt from "markdown-it";
4
import { POSTS_API } from "@/data/constants";
5
6
export const prerender = false;
7
8
const md = new MarkdownIt({
9
	html: true,
10
	linkify: true,
11
	typographer: true,
12
});
13
14
interface Post {
15
	short_id: string;
16
	title: string | null;
17
	slug: string;
18
	published_date: string | null;
19
	meta_description: string | null;
20
	meta_image: string | null;
21
	canonical_url: string | null;
22
	lang: string;
23
	tags: string | null;
24
	content: string;
25
	created_at: string;
26
	updated_at: string;
27
}
28
29
interface PostsListResponse {
30
	posts: Post[];
31
}
32
33
export async function GET() {
34
	try {
35
		const response = await fetch(`${POSTS_API}/posts`);
36
37
		if (!response.ok) {
38
			throw new Error(`HTTP error! status: ${response.status}`);
39
		}
40
41
		const data = (await response.json()) as PostsListResponse;
42
43
		const posts = (data.posts || []).slice().sort((a, b) => {
44
			const dateA = a.published_date ? new Date(a.published_date).getTime() : 0;
45
			const dateB = b.published_date ? new Date(b.published_date).getTime() : 0;
46
			return dateB - dateA;
47
		});
48
49
		const stripMarkdown = (text: string) =>
50
			sanitizeHtml(md.renderInline(text), {
51
				allowedTags: [],
52
				allowedAttributes: {},
53
			});
54
55
		const items = posts.map((post) => {
56
			const rawFallback = post.content
57
				? `${post.content.slice(0, 70)}...`
58
				: post.slug;
59
			const fallback = stripMarkdown(rawFallback);
60
			const htmlContent = md.render(post.content || post.title || "");
61
			const description = post.meta_description || post.title || fallback;
62
63
			return {
64
				title: post.title || fallback,
65
				description,
66
				pubDate: post.published_date
67
					? new Date(post.published_date)
68
					: new Date(0),
69
				link: `/now/${post.slug}`,
70
				content: sanitizeHtml(htmlContent, {
71
					allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
72
				}),
73
			};
74
		});
75
76
		return rss({
77
			title: "Steve's Updates",
78
			description:
79
				"Small updates from my life that don't quite fit into a blog",
80
			site: process.env.SITE_URL || "https://stevedylan.dev",
81
			items: items,
82
		});
83
	} catch (error) {
84
		console.error("Error generating RSS feed:", error);
85
86
		return rss({
87
			title: "Steve's Updates",
88
			description:
89
				"Small updates from my life that don't quite fit into a blog",
90
			site: process.env.SITE_URL || "https://stevedylan.dev",
91
			items: [],
92
		});
93
	}
94
}