// Seed the first admin user (run once at install). // // pnpm --filter @parking/server seed-admin // -> prompts for a username (default "admin") and password // // Non-interactive (install scripts): // ADMIN_USER=admin ADMIN_PASS='strong-pass' pnpm --filter @parking/server seed-admin // // A username may also be passed as an argument. Refuses to overwrite an existing // user unless FORCE=1 (which resets that user's password). import { randomUUID } from "node:crypto"; import { createInterface } from "node:readline/promises"; import { stdin, stdout } from "node:process"; import { createRequire } from "node:module"; const require = createRequire(import.meta.url); const bcrypt = require("bcrypt"); const { createDb, users, eq } = require("@parking/db"); const DEFAULT_USERNAME = "admin"; // Lazily create one readline interface and read answers sequentially through a // single async line iterator — robust whether stdin is a TTY or a pipe (chaining // readline/promises question() over a pipe can drop buffered lines). let rl = null; let lines = null; async function prompt(label) { if (!rl) { rl = createInterface({ input: stdin, output: stdout }); lines = rl[Symbol.asyncIterator](); } stdout.write(label); const { value } = await lines.next(); return (value ?? "").trim(); } // Username: env var > CLI arg > prompt (blank -> default "admin"). let username = process.env.ADMIN_USER ?? process.argv[2]; if (!username) { username = (await prompt(`Admin username [${DEFAULT_USERNAME}]: `)) || DEFAULT_USERNAME; } let password = process.env.ADMIN_PASS; if (!password) { password = await prompt(`Password for "${username}": `); } rl?.close(); if (!password || password.length < 8) { console.error("password must be at least 8 characters"); process.exit(1); } const db = createDb(); const existing = await db.select().from(users).where(eq(users.username, username)).get(); if (existing && process.env.FORCE !== "1") { console.error(`user "${username}" already exists (set FORCE=1 to reset the password)`); process.exit(1); } const passwordHash = await bcrypt.hash(password, 12); if (existing) { await db.update(users).set({ passwordHash, roleId: "admin" }).where(eq(users.id, existing.id)); console.log(`reset password for admin "${username}"`); } else { await db.insert(users).values({ id: randomUUID(), username, passwordHash, roleId: "admin", }); console.log(`created admin "${username}"`); } process.exit(0);