import { z } from "zod"; /** Live checklist shown under the password field. Mirrors {@link passwordField}. */ export const passwordRequirements = [ { label: "At least 8 characters", test: (v: string) => v.length >= 8 }, { label: "One uppercase letter", test: (v: string) => /[A-Z]/.test(v) }, { label: "One lowercase letter", test: (v: string) => /[a-z]/.test(v) }, { label: "One number", test: (v: string) => /\d/.test(v) }, { label: "One special character", test: (v: string) => /[^A-Za-z0-9]/.test(v), }, ] as const; /** * Must stay in step with IAM's `@IsStrongPassword()` on `InitialResetPasswordDto` * — a password this accepts but the API rejects surfaces as an opaque 400. */ export const passwordField = z .string() .min(8, "Password must be at least 8 characters") .regex(/[A-Z]/, "Password must include an uppercase letter") .regex(/[a-z]/, "Password must include a lowercase letter") .regex(/\d/, "Password must include a number") .regex(/[^A-Za-z0-9]/, "Password must include a special character"); export const confirmPasswordField = z .string() .min(1, "Please confirm your password"); export const samePassword = (data: { password: string; confirmPassword: string; }) => data.password === data.confirmPassword; /** Every requirement in {@link passwordRequirements} is satisfied. */ export const meetsAllRequirements = (value: string) => passwordRequirements.every((r) => r.test(value));