import { Hono } from "hono"; import { Env, EmailMetadata } from "../../types"; import { logger } from "../../infrastructure/logger"; import { Layout, clampText } from "./ui"; import { deleteAttachmentsForEmails, deleteKeysWithConcurrency, } from "./helpers"; import { FeedRepository } from "../../domain/feed-repository"; import { FeedId } from "../../domain/value-objects/feed-id"; import { feedRssUrl, feedAtomUrl, feedEmailAddress, } from "../../infrastructure/urls"; import { formatBytes } from "../../domain/format"; import { EmailAddress } from "../../domain/value-objects/email-address"; import { emailsPageScript } from "../../scripts/generated/emails-page"; type AppEnv = { Bindings: Env }; export const emailsRouter = new Hono(); // ── Shared SVG icons ────────────────────────────────────────────────────────── const CopyIcon = () => ( ); const CheckIcon = () => ( ); type CopyFieldProps = { label: string; value: string; display?: string; }; const CopyField = ({ label, value, display }: CopyFieldProps) => (
{label}
{display ?? value}
); type SenderFieldProps = { from: string; feedId: string; }; const SenderField = ({ from, feedId }: SenderFieldProps) => { const parsed = EmailAddress.parse(from); const senderEmail = parsed?.normalized ?? from.trim().toLowerCase(); const senderDomain = parsed?.domain.value ?? ""; return (
From:
{from}
); }; // ── View all emails for a feed ──────────────────────────────────────────────── emailsRouter.get("/feeds/:feedId/emails", async (c) => { const env = c.env; const repo = FeedRepository.from(env); const feedId = c.req.param("feedId"); const message = c.req.query("message"); const count = Number(c.req.query("count") || "0"); const id = FeedId.fromTrusted(feedId); const feedConfig = await repo.getConfig(id); const feedMetadata = await repo.getMetadata(id); if (!feedConfig || !feedMetadata) { return c.text("Feed not found", 404); } const emailAddress = feedEmailAddress(feedId, env); const rssUrl = feedRssUrl(feedId, env); const atomUrl = feedAtomUrl(feedId, env); return c.html(

{feedConfig.title} - Emails

Feed Details

Emails ( {feedMetadata.emails.length})

{message === "bulkDeleted" && (

Deleted {Number.isFinite(count) ? count : 0} email(s).

)} {message === "bulkDeleteNoop" && (

No emails were selected.

)} {feedMetadata.emails.length > 0 ? (
Showing {feedMetadata.emails.length} 0 selected
{feedMetadata.emails.map((email: EmailMetadata) => { const subjectDisplay = clampText(email.subject, 180); const subjectHover = clampText(email.subject, 1000); const attachmentCount = email.attachmentIds?.length ?? 0; const attachmentLabel = `${attachmentCount} attachment${ attachmentCount > 1 ? "s" : "" }`; const sortSubject = subjectHover.toLowerCase(); const sortReceivedAt = String(email.receivedAt); const searchHaystack = clampText( email.subject, 320, ).toLowerCase(); return ( ); })}
Actions
) : (

No emails received yet. Subscribe to newsletters using the email address above.

)}
{/* Config bootstrap — injects dynamic server-side data before the static compiled script */}