import { env } from "cloudflare:workers";
import { all, batch, first, run, stmt } from "./db";
import { hashPassword, randomId } from "./crypto";
import { badRequest, conflict, forbidden, notFoundError } from "./errors";
import { canAdministerAccount } from "./repos";
import { scheduleRevocationSweep, sweepRevokedOrgAccess } from "./pull-guard";
import type { OrgDefaultPermission } from "./repos";
import { assertBelowCap } from "./limits";
import { purgeOrgFollowers } from "./access-revocation";
import type { Viewer } from "~/lib/types";
import { isReservedName } from "~/lib/reserved-names";
import { cleanDisplayName } from "~/lib/validation";
/** Names that still redirect stay retired so old URLs and git remotes can't be taken over; only their owner may reclaim one. */
export async function accountNameTaken(name: string, reclaimingAccountId: string | null = null): Promise<boolean> {
if (isReservedName(name)) return true;
if ((await first<{ id: string }>("SELECT id FROM accounts WHERE name = ?", name)) !== null) return true;
if ((await first("SELECT 1 AS ok FROM retired_account_names WHERE name = ? COLLATE NOCASE", name)) !== null) {
return true;
}
const redirect = await first<{ account_id: string }>(
"SELECT account_id FROM account_redirects WHERE old_name = ? COLLATE NOCASE",
name,
);
return redirect !== null && redirect.account_id !== reclaimingAccountId;
}
/**
* `SIGNUPS_ENABLED` is a boolean: `1`/`true`/`yes`/`on` (any case) open signups, anything else closes them
* (AUTH-A7). Unset keeps the historical default of open.
*/
export function parseSignupsEnabled(raw: string | undefined): boolean {
const value = raw?.trim();
if (value === undefined || value === "") return true;
return /^(1|true|yes|on)$/i.test(value);
}
export function signupsEnabled(): boolean {
return parseSignupsEnabled(env.SIGNUPS_ENABLED);
}