From 6d221a07dd14c75854622fd9924005aae6165d2a Mon Sep 17 00:00:00 2001 From: Julien Herr Date: Thu, 21 May 2026 23:06:18 +0200 Subject: [PATCH] feat(websub): add hub discovery Link headers to RSS and Atom feeds --- src/routes/atom.ts | 6 ++++++ src/routes/rss.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/routes/atom.ts b/src/routes/atom.ts index c05bea5..22479e2 100644 --- a/src/routes/atom.ts +++ b/src/routes/atom.ts @@ -51,11 +51,17 @@ export async function handle(c: Context): Promise { const baseUrl = `https://${env.DOMAIN}`; const atomXml = generateAtomFeed(feedConfig, emailsData, baseUrl, feedId); + const linkHeader = [ + `; rel="hub"`, + `; rel="self"`, + ].join(", "); + return new Response(atomXml, { status: 200, headers: { "Content-Type": "application/atom+xml", "Cache-Control": "max-age=1800", + Link: linkHeader, }, }); } catch (error) { diff --git a/src/routes/rss.ts b/src/routes/rss.ts index 1e6a23d..88e1da3 100644 --- a/src/routes/rss.ts +++ b/src/routes/rss.ts @@ -65,11 +65,17 @@ export async function handle(c: Context): Promise { const rssXml = generateRssFeed(feedConfig, emailsData, baseUrl, feedId); // Return the RSS feed with appropriate content type + const linkHeader = [ + `; rel="hub"`, + `; rel="self"`, + ].join(", "); + return new Response(rssXml, { status: 200, headers: { "Content-Type": "application/rss+xml", "Cache-Control": "max-age=1800", // 30 minutes cache + Link: linkHeader, }, }); } catch (error) {