From da411af6d31d8b828a79dc652816ed2ab05555da Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Tue, 5 May 2026 20:31:11 +0200 Subject: [PATCH] feat: project EmailReadView for email-banner slot, expose auth results --- app/[locale]/page.tsx | 20 +------------------- components/email/email-viewer.tsx | 3 ++- lib/plugin-projection.ts | 25 +++++++++++++++++++++++++ lib/plugin-types.ts | 11 +++++++++++ 4 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 lib/plugin-projection.ts diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index d4c90318..c0de511b 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -60,25 +60,7 @@ import { useConfig } from "@/hooks/use-config"; import { usePluginStore } from "@/stores/plugin-store"; import { useThemeStore } from "@/stores/theme-store"; import { appLifecycleHooks, uiHooks, routerHooks, toastHooks, emailHooks } from "@/lib/plugin-hooks"; -import type { EmailReadView } from "@/lib/plugin-types"; - -function emailToReadView(email: Email): EmailReadView { - return { - id: email.id, - threadId: email.threadId, - mailboxIds: Object.keys(email.mailboxIds || {}).filter(k => email.mailboxIds[k]), - from: (email.from || []).map(a => ({ name: a.name || '', email: a.email })), - to: (email.to || []).map(a => ({ name: a.name || '', email: a.email })), - cc: (email.cc || []).map(a => ({ name: a.name || '', email: a.email })), - subject: email.subject || '', - receivedAt: email.receivedAt, - isRead: !!email.keywords?.['$seen'], - isFlagged: !!email.keywords?.['$flagged'], - hasAttachment: email.hasAttachment, - preview: email.preview || '', - keywords: Object.keys(email.keywords || {}).filter(k => email.keywords[k]), - }; -} +import { emailToReadView } from "@/lib/plugin-projection"; export default function Home() { diff --git a/components/email/email-viewer.tsx b/components/email/email-viewer.tsx index f92b435a..b37f5abe 100644 --- a/components/email/email-viewer.tsx +++ b/components/email/email-viewer.tsx @@ -9,6 +9,7 @@ import { Button } from "@/components/ui/button"; import { Avatar } from "@/components/ui/avatar"; import { formatFileSize, cn, buildMailboxTree, MailboxNode, formatDateTime, generateUUID } from "@/lib/utils"; import { getSecurityStatus, extractListHeaders } from "@/lib/email-headers"; +import { emailToReadView } from "@/lib/plugin-projection"; import { Reply, ReplyAll, @@ -4886,7 +4887,7 @@ export function EmailViewer({
- + {/* Email Body */}
email.mailboxIds[k]), + from: (email.from || []).map(a => ({ name: a.name || '', email: a.email })), + to: (email.to || []).map(a => ({ name: a.name || '', email: a.email })), + cc: (email.cc || []).map(a => ({ name: a.name || '', email: a.email })), + subject: email.subject || '', + receivedAt: email.receivedAt, + isRead: !!email.keywords?.['$seen'], + isFlagged: !!email.keywords?.['$flagged'], + hasAttachment: email.hasAttachment, + preview: email.preview || '', + keywords: Object.keys(email.keywords || {}).filter(k => email.keywords[k]), + auth: email.authenticationResults, + }; +} diff --git a/lib/plugin-types.ts b/lib/plugin-types.ts index 995d1e78..780ec021 100644 --- a/lib/plugin-types.ts +++ b/lib/plugin-types.ts @@ -300,6 +300,17 @@ export interface EmailReadView { hasAttachment: boolean; preview: string; keywords: string[]; + /** + * Parsed Authentication-Results header (SPF, DKIM, DMARC, reverse-DNS). + * Absent on stores that didn't parse the header (e.g. bodies not yet + * fetched). Mirrors the structured shape exposed by the host. + */ + auth?: { + spf?: { result: 'pass' | 'fail' | 'softfail' | 'neutral' | 'none' | 'temperror' | 'permerror'; domain?: string }; + dkim?: { result: 'pass' | 'fail' | 'policy' | 'neutral' | 'temperror' | 'permerror'; domain?: string; selector?: string }; + dmarc?: { result: 'pass' | 'fail' | 'none'; policy?: 'reject' | 'quarantine' | 'none'; domain?: string }; + iprev?: { result: 'pass' | 'fail'; ip?: string }; + }; } export interface DraftView {