refactor(domain): consolidate Feed aggregate invariants in domain/feed.ts

Gather the feed's scattered business rules — expiry, sender allow/block policy,
and the email byte-size budget — into one framework-agnostic module. Expiry was
duplicated across feed-service, email-processor and the rss/atom/entries routes;
the sender policy and trim loop lived inline in email-processor. Each now calls
a single function (isExpired, applySenderPolicy, trimToByteBudget,
resolveExpiresAt). Drops the now-unused MAX_METADATA_EMAILS constant.

Behaviour-preserving; adds feed.test.ts covering every invariant.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Julien Herr
2026-05-23 23:59:15 +02:00
parent 2b3f00f7e3
commit 6b51173722
8 changed files with 250 additions and 114 deletions
+2 -4
View File
@@ -3,6 +3,7 @@ import { Env } from "../types";
import { generateAtomFeed } from "../utils/feed-generator";
import { fetchFeedData } from "../utils/feed-fetcher";
import { baseUrl, feedAtomUrl } from "../utils/urls";
import { isExpired } from "../domain/feed";
export async function handle(c: Context<{ Bindings: Env }>): Promise<Response> {
try {
@@ -15,10 +16,7 @@ export async function handle(c: Context<{ Bindings: Env }>): Promise<Response> {
if (!feedData) {
return new Response("Feed not found", { status: 404 });
}
if (
feedData.feedConfig.expires_at !== undefined &&
feedData.feedConfig.expires_at <= Date.now()
) {
if (isExpired(feedData.feedConfig)) {
return new Response("Feed has expired", { status: 410 });
}