/** * GET/POST /_emdash/api/admin/allowed-domains * * Admin endpoints for managing allowed signup domains. * GET - List all allowed domains * POST - Add a new allowed domain */ import type { APIRoute } from "astro"; export const prerender = false; import { builtinRoleForLevel, roleFromLevel } from "@premium-cms/auth"; import { createKyselyAdapter } from "@premium-cms/auth/adapters/kysely"; import { requirePerm } from "#api/authorize.js"; import { apiError, apiSuccess, handleError } from "#api/error.js"; import { isParseError, parseBody } from "#api/parse.js"; import { allowedDomainCreateBody } from "#api/schemas.js"; import { AuthzRepository } from "#db/repositories/authz.js"; const DOMAIN_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9-]+)+$/; /** * GET - List all allowed domains */ export const GET: APIRoute = async ({ locals }) => { const { emdash, user } = locals; if (!emdash?.db) { return apiError("NOT_CONFIGURED", "Database not configured", 500); } const denied = requirePerm(user, "users:manage"); if (denied) return denied; const adapter = createKyselyAdapter(emdash.db); try { const domains = await adapter.getAllowedDomains(); return apiSuccess({ domains: domains.map((d) => ({ domain: d.domain, defaultRole: d.defaultRole, defaultRoleId: d.defaultRoleId, roleName: roleFromLevel(d.defaultRole), enabled: d.enabled, createdAt: d.createdAt.toISOString(), })), }); } catch (error) { return handleError(error, "Failed to list allowed domains", "DOMAIN_LIST_ERROR"); } }; /** * POST - Add a new allowed domain */ export const POST: APIRoute = async ({ request, locals }) => { const { emdash, user } = locals; if (!emdash?.db) { return apiError("NOT_CONFIGURED", "Database not configured", 500); } const denied = requirePerm(user, "users:manage"); if (denied) return denied; const adapter = createKyselyAdapter(emdash.db); try { const body = await parseBody(request, allowedDomainCreateBody); if (isParseError(body)) return body; // `defaultRoleId` (id or slug) wins; the legacy level maps to a built-in. let defaultRole = body.defaultRole ?? 20; let defaultRoleId: string; if (body.defaultRoleId !== undefined) { const summary = await new AuthzRepository(emdash.db).getRole(body.defaultRoleId); if (!summary) return apiError("UNKNOWN_ROLE", "Role not found", 400); defaultRoleId = summary.id; defaultRole = summary.level as typeof defaultRole; } else { defaultRoleId = `role:${builtinRoleForLevel(defaultRole).slug}`; } // Validate domain format (no protocol, just domain) const cleanDomain = body.domain.toLowerCase().trim(); if (!DOMAIN_REGEX.test(cleanDomain)) { return apiError("VALIDATION_ERROR", "Invalid domain format", 400); } // Check if domain already exists const existing = await adapter.getAllowedDomain(cleanDomain); if (existing) { return apiError("CONFLICT", "Domain already exists", 409); } const domain = await adapter.createAllowedDomain(cleanDomain, defaultRole, defaultRoleId); return apiSuccess( { success: true, domain: { domain: domain.domain, defaultRole: domain.defaultRole, defaultRoleId: domain.defaultRoleId, roleName: roleFromLevel(domain.defaultRole), enabled: domain.enabled, createdAt: domain.createdAt.toISOString(), }, }, 201, ); } catch (error) { return handleError(error, "Failed to create allowed domain", "DOMAIN_CREATE_ERROR"); } };