import { getMessage, searchMessages } from 'kody:@kody/google/gmail' import { DEFAULT_INBOX_MAX, DEFAULT_INBOX_QUERY, skippedSection } from '../format.ts' import { googleInboxSetupError } from '../google-setup.ts' import type { BriefingInput, BriefingItem, BriefingSection } from '../types.ts' type GmailList = { messages?: Array<{ id?: string; threadId?: string }> } type GmailHeader = { name?: string; value?: string } type GmailMessage = { id?: string payload?: { headers?: GmailHeader[] } snippet?: string } function header(message: GmailMessage, name: string): string { const headers = message.payload?.headers || [] return ( headers.find((entry) => String(entry.name || '').toLowerCase() === name.toLowerCase()) ?.value || '' ) } export async function inboxSection(input: BriefingInput): Promise { const account = input.inbox?.account?.trim() || 'personal' const query = input.inbox?.query?.trim() || DEFAULT_INBOX_QUERY const max = Math.min(Math.max(Number(input.inbox?.max) || DEFAULT_INBOX_MAX, 1), 20) if (!account) { return skippedSection( 'inbox', 'Pass inbox.account after connecting bring-your-own Google OAuth with Gmail read scopes.', ) } try { const listed = (await searchMessages({ account, query, maxResults: max, })) as GmailList const ids = (listed.messages || []).map((row) => row.id).filter((id): id is string => Boolean(id)) const items: BriefingItem[] = [] for (const id of ids.slice(0, max)) { const message = (await getMessage({ account, id, format: 'metadata', metadataHeaders: ['Subject', 'From', 'Date'], })) as GmailMessage const subject = header(message, 'Subject') || '(no subject)' const from = header(message, 'From') items.push({ title: subject, detail: from || message.snippet || undefined, label: 'unread', severity: 'notice', }) } return { id: 'inbox', title: 'Inbox', status: items.length ? 'ok' : 'empty', summary: items.length ? `${items.length} message${items.length === 1 ? '' : 's'} for \`${query}\`` : `No messages for \`${query}\``, items, } } catch (error) { throw googleInboxSetupError(error, account) } }