From 3b6016e6c8da4fe789cd29b7c8134e0abecdc67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A9l=20Solano?= Date: Sun, 14 Dec 2025 03:31:49 +0100 Subject: [PATCH] docs: add rss feed (#6733) --- docs/app/blog/_components/blog-list.tsx | 8 ++++- docs/app/blog/rss.xml/route.ts | 11 +++++++ docs/lib/metadata.ts | 11 +++++++ docs/lib/rss.ts | 43 +++++++++++++++++++++++++ docs/package.json | 3 +- pnpm-lock.yaml | 37 ++++++++++++++++----- 6 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 docs/app/blog/rss.xml/route.ts create mode 100644 docs/lib/rss.ts diff --git a/docs/app/blog/_components/blog-list.tsx b/docs/app/blog/_components/blog-list.tsx index 26685accc2..1b1ef48aa3 100644 --- a/docs/app/blog/_components/blog-list.tsx +++ b/docs/app/blog/_components/blog-list.tsx @@ -1,4 +1,5 @@ import { DiscordLogoIcon } from "@radix-ui/react-icons"; +import { RssIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { formatBlogDate } from "@/lib/blog"; @@ -18,7 +19,7 @@ export async function BlogPage() { -
+

Blogs

@@ -55,6 +56,11 @@ export async function BlogPage() { BETTER-AUTH.

+

+ + RSS + +

diff --git a/docs/app/blog/rss.xml/route.ts b/docs/app/blog/rss.xml/route.ts new file mode 100644 index 0000000000..2c7245cdf9 --- /dev/null +++ b/docs/app/blog/rss.xml/route.ts @@ -0,0 +1,11 @@ +import { getRSS } from "@/lib/rss"; + +export const revalidate = false; + +export function GET() { + return new Response(getRSS(), { + headers: { + "Content-Type": "application/rss+xml; charset=utf-8", + }, + }); +} diff --git a/docs/lib/metadata.ts b/docs/lib/metadata.ts index 35fa58cb3a..771bb6ccc6 100644 --- a/docs/lib/metadata.ts +++ b/docs/lib/metadata.ts @@ -19,6 +19,17 @@ export function createMetadata(override: Metadata): Metadata { images: "https://better-auth.com/og.png", ...override.twitter, }, + alternates: { + types: { + "application/rss+xml": [ + { + title: "Better Auth Blog", + url: "https://better-auth.com/blog/rss.xml", + }, + ], + }, + ...override.alternates, + }, }; } diff --git a/docs/lib/rss.ts b/docs/lib/rss.ts new file mode 100644 index 0000000000..b757f48ae1 --- /dev/null +++ b/docs/lib/rss.ts @@ -0,0 +1,43 @@ +import { Feed } from "feed"; +import { blogs } from "./source"; +import { baseUrl } from "./utils"; + +export function getRSS() { + const feed = new Feed({ + title: "Better Auth Blog", + description: "Latest updates, articles, and insights about Better Auth", + generator: "better-auth", + id: `${baseUrl}blog`, + link: `${baseUrl}blog`, + language: "en", + image: `${baseUrl}release-og/blogs.png`, + favicon: `${baseUrl}favicon/favicon-32x32.png`, + copyright: `All rights reserved ${new Date().getFullYear()}, Better Auth Inc.`, + }); + + for (const page of blogs.getPages()) { + const url = page.url.replace("blogs/", "blog/"); + + feed.addItem({ + id: url, + title: page.data.title, + description: page.data.description, + image: page.data.image + ? `${baseUrl}${page.data.image.startsWith("/") ? page.data.image.slice(1) : page.data.image}` + : undefined, + link: `${baseUrl}${url.startsWith("/") ? url.slice(1) : url}`, + date: new Date(page.data.lastModified || page.data.date), + author: page.data.author + ? [ + { + name: page.data.author.name, + avatar: page.data.author.avatar, + link: page.data.author.twitter, + }, + ] + : [], + }); + } + + return feed.rss2(); +} diff --git a/docs/package.json b/docs/package.json index 86ce7f8acb..99c76f8682 100644 --- a/docs/package.json +++ b/docs/package.json @@ -56,6 +56,7 @@ "date-fns": "^4.1.0", "dotenv": "^17.2.2", "embla-carousel-react": "^8.6.0", + "feed": "^5.1.0", "foxact": "^0.2.49", "framer-motion": "^12.23.12", "fumadocs-core": "15.8.3", @@ -88,11 +89,11 @@ "recharts": "^3.1.2", "rehype-highlight": "^7.0.2", "remark": "^15.0.1", - "resend": "^4.0.1", "remark-gfm": "^4.0.1", "remark-mdx": "^3.1.1", "remark-rehype": "^11.1.2", "remark-stringify": "^11.0.0", + "resend": "^4.0.1", "shiki": "^3.13.0", "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b689827cec..e3f54cdcf7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -373,7 +373,7 @@ importers: version: 12.23.12(react-dom@19.2.3(react@19.2.3))(react@19.2.3) geist: specifier: ^1.4.2 - version: 1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)) + version: 1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)) input-otp: specifier: ^1.4.2 version: 1.4.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -485,7 +485,7 @@ importers: version: 2.1.1 geist: specifier: ^1.4.2 - version: 1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)) + version: 1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)) lucide-react: specifier: ^0.542.0 version: 0.542.0(react@19.2.3) @@ -701,6 +701,9 @@ importers: embla-carousel-react: specifier: ^8.6.0 version: 8.6.0(react@19.2.3) + feed: + specifier: ^5.1.0 + version: 5.1.0 foxact: specifier: ^0.2.49 version: 0.2.49(react@19.2.3) @@ -724,7 +727,7 @@ importers: version: 15.8.3(@oramacloud/client@2.1.4)(@tanstack/react-router@1.139.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(algoliasearch@5.36.0)(lucide-react@0.542.0(react@19.2.3))(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.17) geist: specifier: ^1.4.2 - version: 1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)) + version: 1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)) gray-matter: specifier: ^4.0.3 version: 4.0.3 @@ -9129,6 +9132,10 @@ packages: fecha@4.2.3: resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + feed@5.1.0: + resolution: {integrity: sha512-qGNhgYygnefSkAHHrNHqC7p3R8J0/xQDS/cYUud8er/qD9EFGWyCdUDfULHTJQN1d3H3WprzVwMc9MfB4J50Wg==} + engines: {node: '>=20', pnpm: '>=10'} + fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -14218,6 +14225,10 @@ packages: xml-escape@1.1.0: resolution: {integrity: sha512-B/T4sDK8Z6aUh/qNr7mjKAwwncIljFuUP+DO/D5hloYFj+90O88z8Wf7oSucZTHxBAsC1/CTP4rtx/x1Uf72Mg==} + xml-js@1.6.11: + resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} + hasBin: true + xml2js@0.6.0: resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==} engines: {node: '>=4.0.0'} @@ -16580,7 +16591,7 @@ snapshots: postcss: 8.4.49 resolve-from: 5.0.0 optionalDependencies: - expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) + expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) transitivePeerDependencies: - bufferutil - supports-color @@ -16665,7 +16676,7 @@ snapshots: '@expo/json-file': 10.0.7 '@react-native/normalize-colors': 0.81.5 debug: 4.4.3 - expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) + expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) resolve-from: 5.0.0 semver: 7.7.3 xml2js: 0.6.0 @@ -18978,7 +18989,9 @@ snapshots: metro-runtime: 0.83.3 transitivePeerDependencies: - '@babel/core' + - bufferutil - supports-color + - utf-8-validate optional: true '@react-native/normalize-colors@0.74.89': {} @@ -20959,7 +20972,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.28.4 - expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) + expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -22589,7 +22602,7 @@ snapshots: expo-keep-awake@15.0.7(expo@54.0.21)(react@19.2.3): dependencies: - expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) + expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3) react: 19.2.3 expo-linking@7.1.7(expo@54.0.21)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3): @@ -22988,6 +23001,10 @@ snapshots: fecha@4.2.3: {} + feed@5.1.0: + dependencies: + xml-js: 1.6.11 + fetch-blob@3.2.0: dependencies: node-domexception: 1.0.0 @@ -23271,7 +23288,7 @@ snapshots: function-bind@1.1.2: {} - geist@1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)): + geist@1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)): dependencies: next: 16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0) @@ -29272,6 +29289,10 @@ snapshots: xml-escape@1.1.0: {} + xml-js@1.6.11: + dependencies: + sax: 1.4.3 + xml2js@0.6.0: dependencies: sax: 1.4.3