Files
vue-journal-layer/server/routes/rss.xml.ts
Jakub Zych 783426c5d8 feat: Journal author and tag pages, SEO, sitemap source and RSS route
- author pages resolve slug or login and canonicalise to the slug
- tag pages, per-page SEO meta and canonicals that keep ?page=N
- sitemap source pages the API and builds locs from journal.routes
- /rss.xml proxies the API feed with x-forwarded-for
- neutral README; version 0.1.0
2026-10-09 18:06:20 +02:00

33 lines
1.2 KiB
TypeScript

// /rss.xml: the Journal API's RSS 2.0 feed, served from the site origin.
// The visitor's x-forwarded-for is forwarded (plus the peer address) so the
// API's rate limiter keeps one bucket per visitor. 404 when journal.rss is
// false, 502 when the API does not answer.
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig(event)
if ((config.public.journal as { rss?: boolean }).rss === false) {
throw createError({ statusCode: 404, statusMessage: 'Not found' })
}
const base = (config.journal as { apiBase: string }).apiBase
const forwarded = [getRequestHeader(event, 'x-forwarded-for'), getRequestIP(event)]
.filter((v): v is string => typeof v === 'string' && v !== '')
.join(', ')
let body: string
try {
body = await $fetch<string>('/rss', {
baseURL: base,
responseType: 'text',
headers: forwarded ? { 'x-forwarded-for': forwarded } : {},
})
} catch {
setResponseStatus(event, 502)
setResponseHeader(event, 'content-type', 'text/plain; charset=utf-8')
return 'The feed is unavailable.'
}
setResponseHeader(event, 'content-type', 'application/rss+xml; charset=utf-8')
return body
})