import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; import { DynamoDBDocumentClient, GetCommand, PutCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb'; import { config } from '../config.js'; import { normalizeEmail } from '../utils/email.js'; export interface EmailRule { email_address: string; ooo_active?: boolean; ooo_message?: string; ooo_content_type?: string; forwards?: string[]; } export interface BlockList { email_address: string; blocked_patterns: string[]; } export class DynamoRulesService { private doc = DynamoDBDocumentClient.from(new DynamoDBClient({ region: config.awsRegion }), { marshallOptions: { removeUndefinedValues: true }, }); async getRules(email: string): Promise { const email_address = normalizeEmail(email); const resp = await this.doc.send(new GetCommand({ TableName: config.rulesTable, Key: { email_address } })); return (resp.Item as EmailRule) ?? { email_address, ooo_active: false, ooo_message: '', ooo_content_type: 'text/plain', forwards: [] }; } async putRules(rule: EmailRule): Promise { const item: EmailRule = { email_address: normalizeEmail(rule.email_address), ooo_active: !!rule.ooo_active, ooo_message: rule.ooo_message ?? '', ooo_content_type: rule.ooo_content_type ?? 'text/plain', forwards: (rule.forwards ?? []).map(normalizeEmail).filter(Boolean), }; await this.doc.send(new PutCommand({ TableName: config.rulesTable, Item: item })); return item; } async getBlocklist(email: string): Promise { const email_address = normalizeEmail(email); const resp = await this.doc.send(new GetCommand({ TableName: config.blockedTable, Key: { email_address } })); return (resp.Item as BlockList) ?? { email_address, blocked_patterns: [] }; } async putBlocklist(email: string, patterns: string[]): Promise { const item: BlockList = { email_address: normalizeEmail(email), blocked_patterns: patterns.map((p) => p.trim().toLowerCase()).filter(Boolean), }; if (item.blocked_patterns.length === 0) { await this.doc.send(new DeleteCommand({ TableName: config.blockedTable, Key: { email_address: item.email_address } })); return item; } await this.doc.send(new PutCommand({ TableName: config.blockedTable, Item: item })); return item; } }