feat(favicon): per-feed icon from the last sender's domain

Resolve each feed's most recent sender domain and serve its favicon at
GET /favicon/:feedId, falling back to the project icon. Icons are fetched
in the background on ingestion (direct /favicon.ico then a DuckDuckGo
fallback), cached base64 in KV keyed by domain with a 1-week TTL so the
fetch only fires when absent. Exposed via RSS <image> / Atom <icon>/<logo>
and rendered in the admin feed list, plus a landing-page feature card.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Julien Herr
2026-05-23 14:05:14 +02:00
parent d299c8891d
commit eb12f21894
19 changed files with 592 additions and 30 deletions
+2
View File
@@ -45,6 +45,7 @@ export interface FeedConfig {
// Feed metadata interface
export interface FeedMetadata {
emails: EmailMetadata[];
iconDomain?: string; // Most recent sender's domain, used to resolve the feed icon
}
// Email metadata interface (summary info for listing)
@@ -111,6 +112,7 @@ declare global {
put(
key: string,
value: string | ArrayBuffer | ReadableStream | FormData,
options?: { expirationTtl?: number; expiration?: number },
): Promise<void>;
delete(key: string): Promise<void>;
list(options?: {