login-identifier-schema
EditAccepts either a valid email address or canonical username for sign-in.
import * as z from "zod";
const EMAIL_MAX_LENGTH = 254;const USERNAME_MIN_LENGTH = 3;const USERNAME_MAX_LENGTH = 30;const USERNAME_PATTERN = /^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;const codePointLength = (value: string): number => Array.from(value).length;
const loginEmailSchema = z .email({ error: "Enter a valid email address" }) .check( z.maxLength(EMAIL_MAX_LENGTH, { error: `Email must contain at most ${EMAIL_MAX_LENGTH} characters`, }), ) .brand<"Email">();
const loginUsernameSchema = z .string({ error: "Username must be a string" }) .check( z.toLowerCase(), z.normalize("NFC"), z.refine( (value) => codePointLength(value) >= USERNAME_MIN_LENGTH, { error: `Username must contain at least ${USERNAME_MIN_LENGTH} characters`, }, ), z.refine( (value) => codePointLength(value) <= USERNAME_MAX_LENGTH, { error: `Username must contain at most ${USERNAME_MAX_LENGTH} characters`, }, ), z.regex(USERNAME_PATTERN, { error: "Username must use letters or numbers separated by single dots, underscores, or hyphens", }), ) .brand<"Username">();
/** * Accepts either the email or canonical username policy after one trim pass. */export const loginIdentifierSchema = z .string({ error: "Login identifier must be a string" }) .check(z.trim()) .pipe( z.union([loginEmailSchema, loginUsernameSchema], { error: "Enter a valid email address or username", }), ) .meta({ title: "Login identifier", description: "A trimmed email address or canonical lowercase username for sign-in.", examples: ["person@example.com", "person_42"], });
export type LoginIdentifier = z.infer<typeof loginIdentifierSchema>;Download
Section titled “Download”wget -O src/schemas/login-identifier-schema.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/zod-schemas/login-identifier-schema.tstemp_dir="$(mktemp -d)" && bunx degit jrTilak/lazykit/registry/zod-schemas "$temp_dir" && mv "$temp_dir/login-identifier-schema.ts" src/schemas/login-identifier-schema.ts && rm -r "$temp_dir"Examples
Section titled “Examples”import { loginIdentifierSchema, type LoginIdentifier,} from "./login-identifier-schema";
const identifier = loginIdentifierSchema.parse(" Person_42 ");
const startLogin = (value: LoginIdentifier) => { console.log(`Signing in as ${value}`);};
startLogin(identifier);// Output: Signing in as person_42input(string) — An email address or username. Outer whitespace is removed once before either format is evaluated.
Returns
Section titled “Returns”LoginIdentifier, represented as Email | Username.
Email values preserve their casing and have a maximum length of 254.
Username values are lowercased, normalized to NFC, limited to 3–30 Unicode code
points, and restricted to the same alphanumeric and separator policy as
usernameSchema. Invalid input reports one login-identifier error rather than
requiring the caller to choose a branch.