/** * Account names share the URL root with app pages (`/settings`, `/explore`, …), so these can never be * claimed. The list covers every current top-level route plus pages a forge commonly adds later. */ const RESERVED = [ // current routes and raw handlers "acceptable-use", "api", "assets", "attachments", "auth", "avatars", "og", // /og/site.png and /og/feature/.png sit where an account or owner card would "site", "feature", "explore", "ingest", "camo", "email", "unsubscribe", "stripe", "billing", "workbench", "usercontent", "domains", "listen", "preview", "sse", "ws", "scratch", "sites", "forgot-password", "login", "logout", "new", "notifications", "orgs", "projects", "reset-password", "search", "settings", "signup", "verify-email", // auth and accounts "account", "accounts", "join", "oauth", "register", "saml", "session", "sessions", "signin", "signout", "sso", "user", "users", "org", "organization", "organizations", "team", "teams", // product and marketing pages "self-host", "selfhost", "self-hosted", "self-hosting", "install", "get-started", "getting-started", "start", "why", "compare", "open-source", "opensource", "oss", "brand", "logo", "press-kit", "faq", "guides", "learn", "tutorials", "examples", "showcase", "product", "products", "platform", "solutions", "resources", "partners", "about", "blog", "careers", "changelog", "community", "contact", "customers", "docs", "enterprise", "features", "help", "home", "jobs", "legal", "news", "press", "pricing", "privacy", "roadmap", "security", "status", "support", "terms", "tos", "cookies", "dmca", "abuse", "report", "accessibility", "sla", "trust", "compliance", "gdpr", "imprint", "license", "licenses", "sponsor", "donate", "forum", "discord", "chat", "newsletter", "rss", "feed", "feeds", "atom", "developer", "developers", "sdk", "cli", "gfd", "mobile", "desktop", "cloud", "edge", // feature pages that could become top-level "ai", "agents", "mcp", "editor", "hosting", "review", "code-review", "ci", "cd", "cicd", "deploy", "deployments", "copilot", // error and health pages "400", "401", "403", "404", "410", "429", "500", "502", "503", "error", "errors", "maintenance", "offline", "health", "healthz", "ping", "metrics", // forge features "actions", "admin", "administrator", "apps", "archive", "codespaces", "collections", "dashboard", "discussions", "download", "downloads", "events", "gist", "gists", "graphql", "hooks", "integrations", "issues", "marketplace", "packages", "pages", "pull", "pulls", "raw", "releases", "repos", "repositories", "runners", "sponsors", "stars", "topics", "trending", "watching", "webhooks", "wiki", // infrastructure and special values "cdn", "static", "public", "uploads", "images", "img", "media", "files", "git", "mail", "www", "favicon.ico", "robots.txt", "sitemap.xml", "humans.txt", "security.txt", "manifest.json", "site.webmanifest", "gitfor", "gitfor-bot", "bot", "bots", "ghost", "system", "root", "anonymous", "null", "undefined", "nobody", "everyone", "here", "me", "you", "self", "edit", "create", "delete", "index", ] as const; const RESERVED_SET: ReadonlySet = new Set(RESERVED); /** Reserved for the project itself rather than for a route: a site admin may create an org with one of these. */ const ADMIN_CLAIMABLE: ReadonlySet = new Set(["gitfor", "gitfor-bot"]); export function isAdminClaimableName(name: string): boolean { return ADMIN_CLAIMABLE.has(name.toLowerCase()); } export function isReservedName(name: string): boolean { const lower = name.toLowerCase(); return RESERVED_SET.has(lower) || lower.startsWith(".") || lower.startsWith("_"); }