Neah/lib/utils/email-adapter.ts
2025-04-30 20:55:17 +02:00

147 lines
4.6 KiB
TypeScript

/**
* 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,
EmailContent,
EmailAddress,
EmailAttachment,
EmailFlags
} from '@/types/email';
import { normalizeEmailContent } from './email-utils';
/**
* 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,
uid: typeof legacyEmail.uid === 'number' ? legacyEmail.uid : undefined,
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 || undefined,
size: typeof legacyEmail.size === 'number' ? legacyEmail.size : undefined
};
}
/**
* 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 <email@example.com>"
const match = address.match(/^(?:"?([^"]*)"?\s)?<?([^\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'
};
}