/** * DNS record validation status for a single email-related record (MX, SPF, DKIM, DMARC). */ export type TDnsRecordStatus = 'valid' | 'missing' | 'invalid' | 'unchecked'; /** Durable lifecycle of a managed sending domain. Inbound acceptance is independent of this state. */ export type TEmailDomainLifecycleStatus = 'pending' | 'active' | 'failed' | 'deleting'; export type TEmailDnsVerificationOutcome = 'valid' | 'missing' | 'propagation' | 'duplicate' | 'conflict' | 'invalid' | 'lookup-error'; export type TEmailDnsIntentStatus = 'pending' | 'satisfied' | 'valid' | 'conflict' | 'failed' | 'deleting'; export interface IEmailDomainOperationError { code: string; message: string; recordKey?: string; retryable?: boolean; } export interface IEmailDkimMaterial { selector: string; keySize: number; publicKey: string; createdAt: string; validatedAt?: string; promotedAt?: string; retireAfter?: string; } export interface IEmailDnsRecordIntent { key: string; ownerType: 'domain' | 'topology'; ownerId: string; domainId: string; name: string; type: 'MX' | 'TXT' | 'A' | 'AAAA'; value: string; ttl: number; status: TEmailDnsIntentStatus; verificationOutcome?: TEmailDnsVerificationOutcome; satisfactionSource?: 'managed' | 'operator'; effectiveValue?: string; providerRecordId?: string; lastAttemptAt?: string; validatedAt?: string; error?: IEmailDomainOperationError; } export interface IEmailDomainEdgeIdentity { edgeId: string; hostname: string; ipv4?: string; ipv6?: string; observedAt: string; hubReceivedAt: string; } export interface IEmailDomainMxSlot { priority: 10 | 20; edgeId: string; hostname: string; } export interface IEmailDomainDnsRevision { id: string; /** Desired reconciliation generation validated by this revision. Legacy revisions may omit it. */ generation?: number; createdAt: string; activatedAt?: string; selector: string; edgeIdentities: IEmailDomainEdgeIdentity[]; mxSlots: IEmailDomainMxSlot[]; recordKeys: string[]; } export interface IEmailDomainReconciliation { lifecycleStatus: TEmailDomainLifecycleStatus; desiredGeneration: number; activeRevision?: IEmailDomainDnsRevision; pendingRevision?: IEmailDomainDnsRevision; intents: IEmailDnsRecordIntent[]; errors: IEmailDomainOperationError[]; capability?: { egressIdentityProof: 'supported' | 'unsupported'; selectorCorrectSigning: 'supported' | 'unsupported'; }; /** * Provider-managed DomainDoc ids that may contain records owned by this * email domain. undefined means legacy/unknown provenance and blocks * destructive cleanup; [] proves that no provider zone is involved. */ providerZoneIds?: string[]; /** Consecutive retryable reconciliation failures used for bounded backoff. */ retryAttempt?: number; lastAttemptAt?: string; lastSuccessAt?: string; retryAt?: string; deletingAt?: string; /** Provider record ids whose absence must be confirmed before a deletion tombstone can finalize. */ deletingProviderRecordIds?: string[]; } /** * An email domain managed by dcrouter. * * Each email domain is linked to an existing dcrouter DNS domain (dcrouter-hosted * or provider-managed). The DNS management path is inherited from the linked domain * — no separate DNS mode is needed. */ export interface IEmailDomain { id: string; /** Fully qualified email domain name (e.g. 'example.com' or 'mail.example.com'). */ domain: string; /** ID of the linked dcrouter DNS domain — determines how DNS records are managed. */ linkedDomainId: string; /** Optional subdomain prefix (e.g. 'mail' for mail.example.com). Empty/undefined = bare domain. */ subdomain?: string; /** DKIM configuration and key state. */ dkim: IEmailDomainDkim; /** Optional per-domain rate limits. */ rateLimits?: IEmailDomainRateLimits; /** Optional RemoteIngress edge pinning — restricts inbound MX targets and outbound egress to matching edges. */ remoteIngress?: IEmailDomainRemoteIngress; /** DNS record validation status — populated by validateDns(). */ dnsStatus: IEmailDomainDnsStatus; /** Durable desired/active DNS state and reconciliation outcomes. */ reconciliation?: IEmailDomainReconciliation; /** Active outbound DKIM material. Legacy documents may only have `dkim`. */ activeDkim?: IEmailDkimMaterial; /** Staged DKIM material. Never used for signing before promotion. */ pendingDkim?: IEmailDkimMaterial; /** Previously active keys retained for the configured overlap window. */ retiringDkim?: IEmailDkimMaterial[]; createdAt: string; updatedAt: string; } /** * Per-mail-domain RemoteIngress pinning (mirrors IRouteRemoteIngress.edgeFilter semantics). */ export interface IEmailDomainRemoteIngress { /** Edge ids or tags. When set, only matching edges front this domain (inbound MX target + outbound egress). * Absent/empty = all mail-capable edges. */ edgeFilter?: string[]; } export interface IEmailDomainDkim { /** DKIM selector (default: 'default'). */ selector: string; /** RSA key size in bits (default: 2048). */ keySize: number; /** Base64-encoded public key — populated after key generation. */ publicKey?: string; /** Whether automatic key rotation is enabled. */ rotateKeys: boolean; /** Days between key rotations (default: 90). */ rotationIntervalDays: number; /** ISO date of last key rotation. */ lastRotatedAt?: string; /** Days an old selector remains published after promotion (default: 30). */ retirementOverlapDays?: number; } export interface IEmailDomainRateLimits { outbound?: { messagesPerMinute?: number; messagesPerHour?: number; messagesPerDay?: number; }; inbound?: { messagesPerMinute?: number; connectionsPerIp?: number; recipientsPerMessage?: number; }; } export interface IEmailDomainDnsStatus { mx: TDnsRecordStatus; spf: TDnsRecordStatus; dkim: TDnsRecordStatus; dmarc: TDnsRecordStatus; lastCheckedAt?: string; } /** * A single required DNS record for an email domain — used for display / copy-paste. */ export interface IEmailDnsRecord { type: 'MX' | 'TXT' | 'A' | 'AAAA'; name: string; value: string; status: TDnsRecordStatus; }