create-hokage-js-app
Version:
🔥 Best CLI tool to create a MERN stack template. Quick, clean, and customizable.
84 lines (75 loc) • 1.98 kB
text/typescript
import mongoose, { Document, Model, Types } from "mongoose";
import argon2 from "argon2";
import { passwordRegex } from "../validations/auth.validation.js"; // 👈 use `.js` if you're using ESM
export interface IUser extends Document {
name: string;
email: string;
password?: string; // <- because it's `select: false`
refreshToken?: string;
_id: Types.ObjectId;
verifyPassword(candidatePassword: string): Promise<boolean>;
}
interface IUserModel extends Model<IUser> {}
const userSchema = new mongoose.Schema<IUser, IUserModel>(
{
name: {
type: String,
required: [true, "Name is required"],
trim: true,
},
email: {
type: String,
required: [true, "Email is required"],
unique: true,
lowercase: true,
validate: {
validator: (v: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v),
message: (props) =>
`${props.value} is not a valid email address!`,
},
},
password: {
type: String,
required: [true, "Password is required"],
select: false,
validate: {
validator: function (v: string) {
return passwordRegex.test(v);
},
message:
"Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character (@$!%*?&)",
},
},
refreshToken: {
type: String,
select: false,
},
},
{
timestamps: true,
}
);
userSchema.pre<IUser>("save", async function (next) {
if (!this.isModified("password")) return next();
try {
if (this.password) {
this.password = await argon2.hash(this.password);
}
next();
} catch (err) {
next(err as Error);
}
});
userSchema.methods.verifyPassword = async function (
candidatePassword: string
): Promise<boolean> {
if (!this.password) return false;
try {
return await argon2.verify(this.password, candidatePassword);
} catch (err) {
console.error("argon2.verify failed:", err);
return false;
}
};
const User = mongoose.model<IUser, IUserModel>("User", userSchema);
export default User;