import { input, select } from "@inquirer/prompts"; import { Command } from "commander"; import { eq } from "drizzle-orm"; import { toMessage } from "~/server/utils/errors"; import { db } from "../../db/db"; import { sessionsTable, usersTable } from "../../db/schema"; const listUsers = () => { return db.select({ id: usersTable.id, username: usersTable.username }).from(usersTable); }; const changeUsername = async (oldUsername: string, newUsername: string) => { const [user] = await db.select().from(usersTable).where(eq(usersTable.username, oldUsername)); if (!user) { throw new Error(`User "${oldUsername}" not found`); } const normalizedUsername = newUsername.toLowerCase().trim(); const [existingUser] = await db.select().from(usersTable).where(eq(usersTable.username, normalizedUsername)); if (existingUser) { throw new Error(`Username "${newUsername}" is already taken`); } const usernameRegex = /^[a-z0-9_]{3,30}$/; if (!usernameRegex.test(normalizedUsername)) { throw new Error( `Invalid username "${newUsername}". Usernames must be 3-30 characters long and can only contain lowercase letters, numbers, and underscores.`, ); } db.transaction((tx) => { tx.update(usersTable).set({ username: normalizedUsername }).where(eq(usersTable.id, user.id)).run(); tx.delete(sessionsTable).where(eq(sessionsTable.userId, user.id)).run(); }); }; export const changeUsernameCommand = new Command("change-username") .description("Change username for a user") .option("-u, --username ", "Current username of the account") .option("-n, --new-username ", "New username for the account") .action(async (options) => { console.info("\n👤 Zerobyte Change Username\n"); let username = options.username; let newUsername = options.newUsername; try { if (!username) { const users = await listUsers(); if (users.length === 0) { console.error("No users found in the database."); return; } username = await select({ message: "Select a user to change username for:", choices: users.map((u) => ({ name: u.username, value: u.username, })), }); } if (!newUsername) { newUsername = await input({ message: "Enter the new username:", validate: (val) => { const usernameRegex = /^[a-z0-9_]{3,30}$/; return usernameRegex.test(val) ? true : "Username must be 3-30 characters and contain only lowercase letters, numbers, or underscores"; }, }); newUsername = newUsername.toLowerCase().trim(); } await changeUsername(username, newUsername); console.info(`\n✅ Username for "${username}" has been changed to "${newUsername}" successfully.`); } catch (error) { console.error(`\n❌ Error: ${toMessage(error)}`); process.exit(1); } });