import bcrypt from "bcryptjs"; import jwt from "jsonwebtoken"; import db from "./db.js"; import { JWT_SECRET, JWT_EXPIRES_IN } from "./config.js"; function serializeUser(row) { if (!row) return null; return { id: row.id, username: row.username, name: row.name, email: row.email, createdAt: row.created_at ? new Date(row.created_at).toISOString() : null }; } function signToken(userId) { return jwt.sign({ sub: userId }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN }); } export async function registerUser({ username, name, email, password }) { const passwordHash = await bcrypt.hash(password, 10); try { const [result] = await db.query( `INSERT INTO users (username, name, email, password_hash) VALUES (?, ?, ?, ?)`, [username, name, email, passwordHash] ); const user = await getUserById(result.insertId); const token = signToken(user.id); return { user, token }; } catch (error) { if (error?.code === "ER_DUP_ENTRY") { const message = error.sqlMessage || "Duplicate"; if (message.includes("username")) { error.meta = "USERNAME"; } else if (message.includes("email")) { error.meta = "EMAIL"; } } throw error; } } export async function authenticateUser(identifier, password) { const [rows] = await db.query( `SELECT * FROM users WHERE username = ? OR email = ? LIMIT 1`, [identifier, identifier] ); if (rows.length === 0) { const err = new Error("Onjuiste inloggegevens."); err.meta = "INVALID_CREDENTIALS"; throw err; } const row = rows[0]; const ok = await bcrypt.compare(password, row.password_hash); if (!ok) { const err = new Error("Onjuiste inloggegevens."); err.meta = "INVALID_CREDENTIALS"; throw err; } const user = serializeUser(row); const token = signToken(user.id); return { user, token }; } export async function getUserById(id) { const [rows] = await db.query(`SELECT id, username, name, email, created_at FROM users WHERE id = ? LIMIT 1`, [id]); return serializeUser(rows[0]); }