/** * Create an admin user for the dashboard. * * Usage: * npx tsx src/create-admin.ts [display_name] [email] * * Example: * npx tsx src/create-admin.ts justin MySecurePass123 "Justin" "justin@performancewest.net" * * Requires DATABASE_URL environment variable. */ import bcrypt from "bcryptjs"; import pg from "pg"; async function main() { const [, , username, password, displayName, email] = process.argv; if (!username || !password) { console.error("Usage: npx tsx src/create-admin.ts [display_name] [email]"); process.exit(1); } const dbUrl = process.env.DATABASE_URL; if (!dbUrl) { console.error("DATABASE_URL environment variable is required."); process.exit(1); } const pool = new pg.Pool({ connectionString: dbUrl }); try { // Hash password with bcrypt (12 rounds) const hash = await bcrypt.hash(password, 12); const result = await pool.query( `INSERT INTO admin_users (username, password_hash, display_name, email) VALUES ($1, $2, $3, $4) ON CONFLICT (username) DO UPDATE SET password_hash = $2, display_name = $3, email = $4, active = TRUE RETURNING id, username`, [username.toLowerCase().trim(), hash, displayName || username, email || null], ); const user = result.rows[0]; console.log(`Admin user created/updated: ${user.username} (id: ${user.id})`); console.log(`Login at: https://performancewest.net/admin`); } catch (err) { console.error("Failed to create admin user:", err); process.exit(1); } finally { await pool.end(); } } main();