/** * Input validators used by the UI to surface preview feedback before * the user hits the server. The Entropy Softworks application servers * enforce these same rules authoritatively (see `entropy-auth`'s * `password::policy` / `Validation`); these implementations are kept * deliberately strict to avoid false positives on the client. * * Email: a permissive `local@host.tld` shape — anything stricter risks * rejecting valid addresses, and the server validates anyway. * * Password: matches the default `entropy-auth` policy (≥8 chars, mixed * case, digit, symbol). Apps that opt their server into a different * policy can ignore the `valid` result and let the server be the source * of truth. * * Username: 3–30 chars, ASCII alnum + underscore. */ export interface PasswordValidation { valid: boolean; errors: string[]; } export interface UsernameValidation { valid: boolean; error?: string; } const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; const UPPER = /[A-Z]/; const LOWER = /[a-z]/; const DIGIT = /[0-9]/; const SYMBOL = /[!@#$%^&*()_+\-=[\]{}|;:,.<>?]/; const USERNAME = /^[a-zA-Z0-9_]+$/; export function validateEmail(email: string): boolean { return EMAIL.test(email); } export function validatePassword(password: string): PasswordValidation { const errors: string[] = []; if (password.length < 8) { errors.push("Password must be at least 8 characters"); } if (!UPPER.test(password)) { errors.push("Password must contain at least one uppercase letter"); } if (!LOWER.test(password)) { errors.push("Password must contain at least one lowercase letter"); } if (!DIGIT.test(password)) { errors.push("Password must contain at least one number"); } if (!SYMBOL.test(password)) { errors.push("Password must contain at least one special character"); } return { valid: errors.length === 0, errors }; } export function validateUsername(username: string): UsernameValidation { if (username.length < 3 || username.length > 30) { return { valid: false, error: "Username must be between 3 and 30 characters" }; } if (!USERNAME.test(username)) { return { valid: false, error: "Username can only contain letters, numbers, and underscores", }; } return { valid: true }; }