diff --git a/package-lock.json b/package-lock.json index fc737bed..8f9b8918 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@tabler/icons-react": "^3.31.0", "@types/semver": "^7.7.0", "dayjs": "^1.11.13", + "feed": "^5.0.1", "gray-matter": "^4.0.3", "hast-util-from-html": "^2.0.3", "hast-util-select": "^6.0.4", @@ -4737,6 +4738,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/feed": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/feed/-/feed-5.0.1.tgz", + "integrity": "sha512-kOveKLHucVZ6RI91bdWAts9O0L1N2mGzRGVCDQPRnHh4HmgqLdN66Cp/5dMeJZGn/qnBslWliwX37FEBq8DCIA==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=20", + "pnpm": ">=10" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -8606,6 +8620,12 @@ "dev": true, "license": "MIT" }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, "node_modules/scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", @@ -9942,6 +9962,18 @@ "dev": true, "license": "ISC" }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 138230ec..027d0839 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@tabler/icons-react": "^3.31.0", "@types/semver": "^7.7.0", "dayjs": "^1.11.13", + "feed": "^5.0.1", "gray-matter": "^4.0.3", "hast-util-from-html": "^2.0.3", "hast-util-select": "^6.0.4", diff --git a/src/app/blog/feed.xml/route.ts b/src/app/blog/feed.xml/route.ts new file mode 100644 index 00000000..31956b01 --- /dev/null +++ b/src/app/blog/feed.xml/route.ts @@ -0,0 +1,57 @@ +import { getAllPosts } from "@/blog-helpers"; +import { Feed } from "feed"; +import docsConfig from "../../../../docs-config"; + +export const dynamic = "force-static"; +export async function GET() { + const allPosts = getAllPosts(); + allPosts.sort( + (a, b) => + new Date(b.frontmatter.created_at).valueOf() - + new Date(a.frontmatter.created_at).valueOf() + ); + + const feed = new Feed({ + title: "Prometheus Blog", + description: "The Prometheus blog", + id: `${docsConfig.siteUrl}/`, + link: `${docsConfig.siteUrl}/blog/`, + copyright: `Prometheus Authors ${new Date().getFullYear()}`, + language: "en", + updated: allPosts[0].frontmatter.created_at, + author: { + name: "Prometheus Authors", + link: `${docsConfig.siteUrl}/blog/`, + }, + favicon: "TODO", + image: "TODO", + feedLinks: { + atom: `${docsConfig.siteUrl}/blog/feed.xml`, + }, + }); + + allPosts.forEach(({ frontmatter, path }) => { + feed.addItem({ + title: frontmatter.title, + id: `${docsConfig.siteUrl}${path}`, + link: `${docsConfig.siteUrl}${path}`, + description: frontmatter.excerpt, + date: new Date(frontmatter.created_at), + published: new Date(frontmatter.created_at), + author: [ + { + name: frontmatter.author_name, + link: `${docsConfig.siteUrl}/blog/`, + }, + ], + // TODO: Include rendered Markdown as content. + }); + }); + const xml = feed.atom1(); + return new Response(xml, { + headers: { + "Content-Type": "application/atom+xml", + "Cache-Control": "s-maxage=3600, stale-while-revalidate=59", + }, + }); +}