import { Router } from 'express' import bcrypt from 'bcrypt' import { validateBody } from '../middleware/validate.js' import { asyncHandler } from '../utils/asyncHandler.js' import { AppError } from '../middleware/error.js' import { getDb } from '../db/database.js' import * as userRepo from '../repositories/userRepo.js' import * as settingsRepo from '../repositories/settingsRepo.js' import { setupSchema } from '../validators/setupSchemas.js' import { signToken } from '../utils/tokens.js' const router = Router() const SALT_ROUNDS = 10 function getSiteTitle(): string | null { return settingsRepo.getSetting('site_name') ?? null } // GET /api/setup/status router.get( '/status', asyncHandler(async (_req, res) => { const title = getSiteTitle() res.json({ completed: !!title, siteTitle: title ?? undefined, }) }) ) // POST /api/setup router.post( '/', validateBody(setupSchema), asyncHandler(async (req, res) => { const db = getDb() // Atomic transaction prevents race conditions between concurrent setup requests const tx = db.transaction(() => { const title = settingsRepo.getSetting('site_name') if (title) { throw new AppError(400, 'Setup already completed') } const userCount = userRepo.countUsers() if (userCount > 0) { throw new AppError(400, 'Users already exist') } const { email, password, displayName, siteTitle, language, smtpHost, smtpPort, smtpUser, smtpPass, smtpFrom, smtpSecure, appUrl, } = req.body const passwordHash = bcrypt.hashSync(password, SALT_ROUNDS) const { id } = userRepo.createUser({ email, passwordHash, displayName, role: 'admin', emailVerified: 1, }) const settings: Array<[string, string]> = [ ['site_name', siteTitle?.trim() || 'BrainWave'], ['site_language', language || 'en'], ['maintenance_mode', 'false'], ] if (smtpHost !== undefined) settings.push(['smtp_host', smtpHost]) if (smtpPort !== undefined) settings.push(['smtp_port', smtpPort]) if (smtpUser !== undefined) settings.push(['smtp_user', smtpUser]) if (smtpPass !== undefined) settings.push(['smtp_pass', smtpPass]) if (smtpFrom !== undefined) settings.push(['smtp_from', smtpFrom]) if (smtpSecure !== undefined) settings.push(['smtp_secure', smtpSecure]) if (appUrl !== undefined) settings.push(['app_url', appUrl]) settingsRepo.setSettingsBatch(settings) return { id, email, displayName } }) const { id, email, displayName } = tx() const token = signToken({ userId: id, email, displayName, role: 'admin', }) res.status(201).json({ message: 'Setup completed successfully', token, user: { id, email, displayName, role: 'admin', }, }) }) ) export default router