import { env } from "cloudflare:workers";
import { batch, first, stmt } from "./db";
import { hashPassword, randomId } from "./crypto";
import { badRequest, conflict } from "./errors";
export async function accountNameTaken(name: string): Promise<boolean> {
return (await first<{ id: string }>("SELECT id FROM accounts WHERE name = ?", name)) !== null;
}
/** A claimed name stops redirecting to its previous owner. */
function releaseNameRedirects(name: string): D1PreparedStatement[] {
return [
stmt("DELETE FROM account_redirects WHERE old_name = ?", name),
stmt("DELETE FROM repo_redirects WHERE owner_name = ?", name),
];
}
export function signupsEnabled(): boolean {
return env.SIGNUPS_ENABLED !== "false";
}
export function githubOAuthEnabled(): boolean {
return Boolean(env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET);
}
export async function createUser(input: {
name: string;
email: string;
password: string | null;
githubId: string | null;
displayName: string | null;
}): Promise<string> {
if (await accountNameTaken(input.name)) throw conflict("That username is already taken");
if (await first<{ account_id: string }>("SELECT account_id FROM users WHERE email = ?", input.email)) {
throw conflict("An account with that email already exists");
}
const isFirstUser = (await first<{ count: number }>("SELECT COUNT(*) AS count FROM users"))?.count === 0;
if (!isFirstUser && !signupsEnabled()) throw badRequest("Sign ups are disabled on this instance");
const id = randomId();
const passwordHash = input.password ? await hashPassword(input.password) : null;