feat(app): detect native feeds during email ingestion

Wire extractFeedLinks + detectNativeFeeds into storeEmail so that RSS/Atom/JSON
feed <link> tags in the newsletter HTML are detected and stored per-sender on the
feed metadata.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
Julien HerrandClaude Sonnet 4.6 committed 2026-05-25 17:22:05 +02:00
1 parent ee0e7eef5d
commit 5362d478e3
2 files changed
+72 -6

No files matched your search

+54
View File
@@ -994,3 +994,57 @@ describe("processEmail — unsubscribe capture", () => {
expect(metadata.unsubscribe).toBeUndefined();
});
});
describe("native feed detection on ingest", () => {
let env: ReturnType<typeof createMockEnv>;
beforeEach(async () => {
env = createMockEnv();
await env.EMAIL_STORAGE.put(
`feed:${VALID_FEED_ID}:config`,
JSON.stringify({}),
);
await seedInboundIndex(env, VALID_FEED_ID);
});
it("stores detected native feeds on the feed metadata (TEST A)", async () => {
const result = await processEmail(
makeInput({
from: "[email protected]",
senders: ["[email protected]"],
content:
'<html><head><link rel="alternate" type="application/rss+xml" href="https://blog.example.com/feed.xml"></head><body>hello</body></html>',
}),
env as any,
);
expect(result.ok).toBe(true);
const metadata = (await env.EMAIL_STORAGE.get(
`feed:${VALID_FEED_ID}:metadata`,
"json",
)) as {
nativeFeeds?: Record<string, Array<{ url: string; type: string }>>;
};
expect(Object.values(metadata.nativeFeeds!).flat()).toEqual([
{ url: "https://blog.example.com/feed.xml", type: "rss" },
]);
});
it("does not store nativeFeeds when no feed links are found (TEST B)", async () => {
const result = await processEmail(
makeInput({
content: "<p>no feed here</p>",
}),
env as any,
);
expect(result.ok).toBe(true);
const metadata = (await env.EMAIL_STORAGE.get(
`feed:${VALID_FEED_ID}:metadata`,
"json",
)) as { nativeFeeds?: Record<string, unknown> };
expect(metadata.nativeFeeds).toBeUndefined();
});
});