Files
kill-the-news/src/routes/json.ts
T
Julien Herr 1332362005 fix(feeds): self link uses configured domain, not request host
The RSS/Atom/JSON self link was derived from the request origin, leaking
the workers.dev host when reached directly instead of via the custom
domain. Use the configured-domain URL builders so self matches alternate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 18:38:38 +02:00

52 lines
1.5 KiB
TypeScript

import { Context } from "hono";
import { Env } from "../types";
import { generateJsonFeed } from "../infrastructure/feed-generator";
import { fetchFeedData } from "../application/feed-fetcher";
import { baseUrl, feedJsonUrl } from "../infrastructure/urls";
import { isExpired } from "../domain/feed";
import { FeedId } from "../domain/value-objects/feed-id";
export async function handle(c: Context<{ Bindings: Env }>): Promise<Response> {
try {
const feedId = c.req.param("feedId");
if (!feedId) {
return new Response("Feed ID is required", { status: 400 });
}
const feedData = await fetchFeedData(FeedId.unchecked(feedId), c.env);
if (!feedData) {
return new Response("Feed not found", { status: 404 });
}
if (isExpired(feedData.feedConfig)) {
return new Response("Feed has expired", { status: 410 });
}
const base = baseUrl(c.env);
const selfUrl = feedJsonUrl(feedId, c.env);
const jsonFeed = generateJsonFeed(
feedData.feedConfig,
feedData.emails,
base,
feedId,
selfUrl,
);
const linkHeader = [
`<${base}/hub>; rel="hub"`,
`<${selfUrl}>; rel="self"`,
].join(", ");
return new Response(jsonFeed, {
status: 200,
headers: {
"Content-Type": "application/feed+json",
"Cache-Control": "max-age=1800",
"X-Robots-Tag": "noindex",
Link: linkHeader,
},
});
} catch (error) {
console.error("Error generating JSON feed:", error);
return new Response("Internal Server Error", { status: 500 });
}
}