aegis-auth
Version:
A credentials-based auth solution for Next.js (and other Node projects) with IP rate-limiting, account lockouts, and sessions in DB.
77 lines • 3.23 kB
JavaScript
import { z } from "zod";
// Enhanced validation messages with more descriptive language.
const validationMessages = {
required: (field) => `${field} is required.`,
length: {
min: (field, length) => `${field} must be at least ${length} characters long.`,
max: (field, length) => `${field} must not exceed ${length} characters.`,
},
format: {
email: "Please provide a valid email address.",
username: "Username must be lowercase and may only contain letters, numbers, and underscores.",
displayName: "Display name may only contain letters, numbers, underscores, and spaces.",
password: "Password must include at least one uppercase letter, one lowercase letter, one number, and one special character.",
},
password: {
match: "Passwords do not match.",
},
};
// Reusable schema factory that automatically trims input and validates length/format.
const createStringSchema = (options) => {
const { field, minLength, maxLength, regex, regexMessage } = options;
let schema = z.string({ required_error: validationMessages.required(field) });
if (minLength !== undefined) {
schema = schema.min(minLength, {
message: validationMessages.length.min(field, minLength),
});
}
if (maxLength !== undefined) {
schema = schema.max(maxLength, {
message: validationMessages.length.max(field, maxLength),
});
}
if (regex) {
schema = schema.regex(regex, {
message: regexMessage || `${field} is in an invalid format.`,
});
}
return schema.transform((val) => val.trim());
};
// Password schema that enforces a complexity requirement.
// The regex below ensures at least one lowercase, one uppercase, one digit, and one special character.
const passwordComplexityRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).+$/;
export const getPasswordSchema = (type) => createStringSchema({
field: type,
minLength: 8,
maxLength: 32,
regex: passwordComplexityRegex,
regexMessage: validationMessages.format.password,
});
// Email schema: also validates that the string is a valid email.
export const getEmailSchema = () => z
.string()
.min(1, { message: validationMessages.length.min("Email", 1) })
.email({ message: validationMessages.format.email })
.transform((val) => val.trim());
// Username schema: enforces lowercase letters, numbers, and underscores only.
export const getUsernameSchema = () => createStringSchema({
field: "Username",
minLength: 1,
maxLength: 48,
regex: /^[a-z0-9_]+$/,
regexMessage: validationMessages.format.username,
});
// Display name schema: only letters, numbers, underscores, and spaces; optional.
export const getDisplayNameSchema = () => createStringSchema({
field: "Display name",
maxLength: 48,
regex: /^[a-zA-Z0-9_ ]*$/,
regexMessage: validationMessages.format.displayName,
}).optional();
// Avatar URL schema: must be a valid URL if provided.
export const getAvatarUrlSchema = () => z
.string()
.url({ message: "Avatar URL must be a valid URL." })
.transform((val) => val.trim())
.optional();
//# sourceMappingURL=templates.js.map