/** * Email Adapter Utility * * This utility provides adapter functions to convert legacy email * formats to the standardized EmailMessage format. * * Use these functions to migrate code gradually without breaking changes. */ import { EmailMessage, EmailAddress, EmailAttachment } from '@/lib/types'; // Define a local interface for email flags structure interface EmailFlags { seen: boolean; flagged: boolean; answered: boolean; deleted: boolean; draft: boolean; } /** * Normalize email content from various formats to our standard structure */ function normalizeEmailContent(email: any): { text: string; html: string; isHtml: boolean; direction: string } { // Initialize with default values let text = ''; let html = ''; let isHtml = false; // Extract content from various possible formats if (email.content) { if (typeof email.content === 'string') { // If content is a string, determine if it's HTML or plain text if (email.content.includes(']*>/g, ''); // Basic HTML stripping isHtml = true; } else { text = email.content; html = ''; } } else if (typeof email.content === 'object') { // If content is already an object, try to read text/html properties text = email.content.text || email.content.plainText || ''; html = email.content.html || ''; isHtml = !!email.content.isHtml || !!html; } } else { // Try to find content in other common properties if (email.html) { html = email.html; isHtml = true; } if (email.text) { text = email.text; } else if (email.plainText) { text = email.plainText; } // If we have HTML but no text, create a basic text version if (html && !text) { text = html.replace(/<[^>]*>/g, ''); } } // Return standardized content object return { text, html, isHtml, direction: 'ltr' // Default to left-to-right }; } /** * Convert a legacy email format to our standardized EmailMessage format * * This adapter function handles all the various ways email data might be structured * in the legacy codebase and converts it to our new standardized format. */ export function adaptLegacyEmail(legacyEmail: any): EmailMessage { if (!legacyEmail) { throw new Error('Cannot adapt a null or undefined email'); } // Handle case where it's already in the right format if ( legacyEmail.content && typeof legacyEmail.content === 'object' && 'isHtml' in legacyEmail.content && 'text' in legacyEmail.content ) { return legacyEmail as EmailMessage; } // Create normalized content const normalizedContent = normalizeEmailContent(legacyEmail); // Normalize flags to standard format let normalizedFlags: EmailFlags = { seen: false, flagged: false, answered: false, deleted: false, draft: false }; // Handle different possible formats for flags if (legacyEmail.flags) { if (typeof legacyEmail.flags === 'object' && !Array.isArray(legacyEmail.flags)) { // Object format: { seen: true, flagged: false, ... } normalizedFlags = { seen: !!legacyEmail.flags.seen, flagged: !!legacyEmail.flags.flagged, answered: !!legacyEmail.flags.answered, deleted: !!legacyEmail.flags.deleted, draft: !!legacyEmail.flags.draft }; } else if (Array.isArray(legacyEmail.flags)) { // Array format: ['\\Seen', '\\Flagged', ...] normalizedFlags.seen = legacyEmail.flags.includes('\\Seen'); normalizedFlags.flagged = legacyEmail.flags.includes('\\Flagged'); normalizedFlags.answered = legacyEmail.flags.includes('\\Answered'); normalizedFlags.deleted = legacyEmail.flags.includes('\\Deleted'); normalizedFlags.draft = legacyEmail.flags.includes('\\Draft'); } } // Normalize attachments to standard format const normalizedAttachments: EmailAttachment[] = Array.isArray(legacyEmail.attachments) ? legacyEmail.attachments.map((att: any) => ({ filename: att.filename || att.name || 'attachment', contentType: att.contentType || att.type || 'application/octet-stream', content: att.content || att.data || undefined, size: att.size || 0, contentId: att.contentId || att.cid || undefined })) : []; // Return a normalized EmailMessage return { id: legacyEmail.id || legacyEmail.uid?.toString() || `email-${Date.now()}`, messageId: legacyEmail.messageId, subject: legacyEmail.subject || '(No subject)', from: Array.isArray(legacyEmail.from) ? legacyEmail.from : [], to: Array.isArray(legacyEmail.to) ? legacyEmail.to : [], cc: Array.isArray(legacyEmail.cc) ? legacyEmail.cc : undefined, bcc: Array.isArray(legacyEmail.bcc) ? legacyEmail.bcc : undefined, date: legacyEmail.date || new Date(), flags: normalizedFlags, preview: legacyEmail.preview || '', content: normalizedContent, attachments: normalizedAttachments, folder: legacyEmail.folder || 'INBOX', contentFetched: true, size: typeof legacyEmail.size === 'number' ? legacyEmail.size : 0, hasAttachments: normalizedAttachments.length > 0, accountId: legacyEmail.accountId }; } /** * Helper function to detect if an object is an EmailAddress */ export function isEmailAddress(obj: any): obj is EmailAddress { return obj && typeof obj === 'object' && 'address' in obj && typeof obj.address === 'string'; } /** * Convert legacy email address format to standardized EmailAddress format */ export function adaptEmailAddress(address: any): EmailAddress { if (isEmailAddress(address)) { return { name: address.name || '', address: address.address }; } if (typeof address === 'string') { // Try to extract name and address from string like "Name " const match = address.match(/^(?:"?([^"]*)"?\s)?]+@[^\s>]+)>?$/); if (match) { return { name: match[1] || '', address: match[2] }; } // If no match, assume it's just an email address return { name: '', address }; } // Return a placeholder if we can't parse the address return { name: '', address: 'unknown@example.com' }; }