/** * Email Value Object * * Encapsulates email address validation and behavior * * Business Rules: * - Email must be valid format * - Email is case-insensitive (stored lowercase) * - Email is immutable */ export class Email { private readonly value: string; private constructor(email: string) { this.value = email; } static create(email: string): Email { if (!email || email.trim().length === 0) { throw new Error('Email cannot be empty.'); } const normalized = email.trim().toLowerCase(); if (!Email.isValid(normalized)) { throw new Error(`Invalid email format: ${email}`); } return new Email(normalized); } private static isValid(email: string): boolean { // RFC 5322 simplified email regex const emailPattern = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/; return emailPattern.test(email); } getValue(): string { return this.value; } getDomain(): string { return this.value.split('@')[1]; } getLocalPart(): string { return this.value.split('@')[0]; } equals(other: Email): boolean { return this.value === other.value; } toString(): string { return this.value; } }