/** * SessionLifetime Value Object * * Represents the lifetime of an authentication session with expiry tracking. * Handles validation of session expiry dates with a configurable buffer window. */ export class SessionLifetime { private readonly expiry: Date | null; private readonly bufferMinutes: number; constructor(expiry: Date | null, bufferMinutes: number = 5) { if (expiry !== null) { if (isNaN(expiry.getTime())) { throw new Error('Invalid expiry date provided'); } // Allow dates within buffer window to support checking expiry of recently expired sessions const bufferMs = bufferMinutes * 60 * 1000; const expiryWithBuffer = expiry.getTime() + bufferMs; if (expiryWithBuffer < Date.now()) { throw new Error('Expiry date cannot be in the past'); } } this.expiry = expiry; this.bufferMinutes = bufferMinutes; } /** * Check if the session is expired. * Considers the buffer time - sessions within the buffer window are treated as expired. * * @returns true if expired or expiring soon (within buffer), false otherwise */ isExpired(): boolean { if (this.expiry === null) { return false; } const bufferMs = this.bufferMinutes * 60 * 1000; const expiryWithBuffer = this.expiry.getTime() - bufferMs; return Date.now() >= expiryWithBuffer; } /** * Check if the session is expiring soon (within buffer window). * * @returns true if expiring within buffer window, false otherwise */ isExpiringSoon(): boolean { if (this.expiry === null) { return false; } const bufferMs = this.bufferMinutes * 60 * 1000; const now = Date.now(); const expiryTime = this.expiry.getTime(); const expiryWithBuffer = expiryTime - bufferMs; return now >= expiryWithBuffer && now < expiryTime; } /** * Get the expiry date. * * @returns The expiry date or null if no expiration */ getExpiry(): Date | null { return this.expiry; } /** * Get remaining time until expiry in milliseconds. * * @returns Milliseconds until expiry, or Infinity if no expiration */ getRemainingTime(): number { if (this.expiry === null) { return Infinity; } const remaining = this.expiry.getTime() - Date.now(); return Math.max(0, remaining); } }