Files
supabase/apps/www/lib/rss.tsx
T
Francesco Sansalvadore 7c20cc574c feat(www): new changelog sync (#47880)
## What kind of change does this PR introduce?

Sync changelog from private supabase/changelog.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Changelog entries now come from the structured changelog repository.
* Added filters for change type, product stage, and self-hosted impact.
* Updated badge UI for affected products and change types with filter
links.
* Changelog detail sidebar now shows lifecycle stage, sunset dates, and
self-hosted impact (when available).

* **Improvements**
  * Product category discovery and filtering now use affected products.
  * Discussion links show only when legacy discussion data is present.
* RSS feeds and generated changelog markdown now use the updated
metadata.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-23 11:16:39 +02:00

99 lines
3.4 KiB
TypeScript

import authors from 'lib/authors.json'
const dayjs = require('dayjs')
var utc = require('dayjs/plugin/utc')
var advancedFormat = require('dayjs/plugin/advancedFormat')
dayjs.extend(utc)
dayjs.extend(advancedFormat)
export function xmlEncodeRss(str: string | undefined | null): string {
if (str === undefined || str === null) {
return ''
}
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
}
const generateRssItem = (post: any): string => {
const encodedTitle = xmlEncodeRss(post.title)
const encodedPath = xmlEncodeRss(post.path)
const encodedDescription = xmlEncodeRss(post.description)
const formattedDate = dayjs(post.date)
.utcOffset(0, true)
.startOf('day')
.format('ddd, DD MMM YYYY HH:mm:ss [-0700]')
return `<item>
<guid>https://supabase.com${encodedPath}</guid>
<title>${encodedTitle}</title>
<link>https://supabase.com${encodedPath}</link>
<description>${encodedDescription}</description>
<pubDate>${formattedDate}</pubDate>
</item>
`
}
export type ChangelogRssItemInput = {
title: string
slug: string
sortDate: string
affectedProducts?: string[]
}
/** Implemented in `./changelog-rss.mjs` (used by `scripts/generateStaticContent.mjs`). */
export { generateChangelogRssXml } from './changelog-rss.mjs'
// This utility generates RSS feeds for specialized content:
// 1. Customer stories RSS feed (customers-rss.xml) - used by pages/customers.tsx via getStaticProps
// 2. Author-specific PlanetPG RSS feeds (planetpg-{authorID}-rss.xml) - filtered feeds for individual authors
// 3. Changelog RSS (changelog-rss.xml) — built in generateStaticContent.mjs via ./changelog-rss.mjs
//
// Note: The main blog RSS feed (rss.xml) containing all blog posts is generated separately
// in generateStaticContent.mjs during the build process. This file is NOT used for the main blog feed.
//
// Usage:
// - Without authorID: Generates generic RSS feed (used for customer stories)
// - With authorID: Generates author-specific feed with custom title/description for PlanetPG authors
export const generateRss = (posts: any[], authorID?: string): string => {
const authorInfo = authors.find((item) => item.author_id === authorID)
const formattedDate = dayjs(posts[0].date)
.utcOffset(0, true)
.startOf('day')
.format('ddd, DD MMM YYYY HH:mm:ss [-0700]')
if (authorID) {
return `
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>'Postgres | Supabase Blog</title>
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from ${authorInfo?.author} at Supabase</description>
<language>en</language>
<lastBuildDate>${formattedDate}</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-${authorID}-rss.xml" rel="self" type="application/rss+xml"/>
${posts.map(generateRssItem).join('')}
</channel>
</rss>
`
} else {
return `
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Blog - Supabase</title>
<link>https://supabase.com</link>
<description>Latest news from Supabase</description>
<language>en</language>
<lastBuildDate>${formattedDate}</lastBuildDate>
<atom:link href="https://supabase.com/rss.xml" rel="self" type="application/rss+xml"/>
${posts.map(generateRssItem).join('')}
</channel>
</rss>
`
}
}