mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## 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 -->
116 lines
3.6 KiB
JavaScript
116 lines
3.6 KiB
JavaScript
/**
|
|
* Pure ESM changelog RSS document builder (used by generateStaticContent.mjs and re-exported from rss.tsx).
|
|
* @typedef {{ slug: string; title: string; sortDate: string; affectedProducts?: string[] }} ChangelogRssItemInput
|
|
*/
|
|
import dayjs from 'dayjs'
|
|
import utc from 'dayjs/plugin/utc.js'
|
|
|
|
dayjs.extend(utc)
|
|
|
|
function xmlEncodeRss(str) {
|
|
if (str === undefined || str === null) return ''
|
|
return String(str)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''')
|
|
}
|
|
|
|
function formatRssPubDate(isoOrDate) {
|
|
return `${dayjs(isoOrDate).utc().startOf('day').format('ddd, DD MMM YYYY HH:mm:ss')} +0000`
|
|
}
|
|
|
|
function buildItemsXml(sorted) {
|
|
return sorted
|
|
.map((e) => {
|
|
const encodedTitle = xmlEncodeRss(e.title)
|
|
const canonicalUrl = `https://supabase.com/changelog/${e.slug}`
|
|
const encodedCanonical = xmlEncodeRss(canonicalUrl)
|
|
const pubDate = formatRssPubDate(e.sortDate)
|
|
return ` <item>
|
|
<guid isPermaLink="true">${encodedCanonical}</guid>
|
|
<title>${encodedTitle}</title>
|
|
<link>${encodedCanonical}</link>
|
|
<pubDate>${pubDate}</pubDate>
|
|
</item>`
|
|
})
|
|
.join('\n')
|
|
}
|
|
|
|
/**
|
|
* Converts a display label into a lowercase, URL-safe filename slug.
|
|
* e.g. "Edge Functions" → "edge-functions", "Data APIs" → "data-apis"
|
|
* @param {string} label
|
|
*/
|
|
export function labelToFileSlug(label) {
|
|
return label
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-+|-+$/g, '')
|
|
}
|
|
|
|
/** @param {ChangelogRssItemInput[]} entries */
|
|
export function generateChangelogRssXml(entries) {
|
|
const sorted = [...entries].sort(
|
|
(a, b) => dayjs(b.sortDate).valueOf() - dayjs(a.sortDate).valueOf()
|
|
)
|
|
|
|
const lastBuildDate = sorted[0]?.sortDate
|
|
? formatRssPubDate(sorted[0].sortDate)
|
|
: formatRssPubDate(dayjs().toISOString())
|
|
|
|
return `
|
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
<channel>
|
|
<title>Supabase Changelog</title>
|
|
<link>https://supabase.com/changelog</link>
|
|
<description>Product updates and improvements from Supabase</description>
|
|
<language>en</language>
|
|
<lastBuildDate>${lastBuildDate}</lastBuildDate>
|
|
<atom:link href="https://supabase.com/changelog-rss.xml" rel="self" type="application/rss+xml"/>
|
|
${buildItemsXml(sorted)}
|
|
</channel>
|
|
</rss>
|
|
`
|
|
}
|
|
|
|
/**
|
|
* Generates a tag-filtered RSS feed.
|
|
* @param {ChangelogRssItemInput[]} allEntries - all entries, with `affected_products` display strings
|
|
* @param {{ displayLabel: string }} tag
|
|
*/
|
|
export function generateChangelogTagRssXml(allEntries, tag) {
|
|
const { displayLabel } = tag
|
|
const fileSlug = labelToFileSlug(displayLabel)
|
|
|
|
const filtered = allEntries.filter((e) =>
|
|
(e.affectedProducts ?? []).some(
|
|
(product) => product.toLowerCase() === displayLabel.toLowerCase()
|
|
)
|
|
)
|
|
const sorted = [...filtered].sort(
|
|
(a, b) => dayjs(b.sortDate).valueOf() - dayjs(a.sortDate).valueOf()
|
|
)
|
|
|
|
const lastBuildDate = sorted[0]?.sortDate
|
|
? formatRssPubDate(sorted[0].sortDate)
|
|
: formatRssPubDate(dayjs().toISOString())
|
|
|
|
const feedUrl = `https://supabase.com/changelog-rss/${fileSlug}.xml`
|
|
|
|
return `
|
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
<channel>
|
|
<title>Supabase Changelog · ${displayLabel}</title>
|
|
<link>https://supabase.com/changelog</link>
|
|
<description>${displayLabel} updates and improvements from Supabase</description>
|
|
<language>en</language>
|
|
<lastBuildDate>${lastBuildDate}</lastBuildDate>
|
|
<atom:link href="${feedUrl}" rel="self" type="application/rss+xml"/>
|
|
${buildItemsXml(sorted)}
|
|
</channel>
|
|
</rss>
|
|
`
|
|
}
|