{"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/admin/allowed-domains/index.ts"],"sourcesContent":["/**\n * GET/POST /_emdash/api/admin/allowed-domains\n *\n * Admin endpoints for managing allowed signup domains.\n * GET - List all allowed domains\n * POST - Add a new allowed domain\n */\n\nimport type { APIRoute } from \"astro\";\n\nexport const prerender = false;\n\nimport { builtinRoleForLevel, roleFromLevel } from \"@premium-cms/auth\";\nimport { createKyselyAdapter } from \"@premium-cms/auth/adapters/kysely\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { allowedDomainCreateBody } from \"#api/schemas.js\";\nimport { AuthzRepository } from \"#db/repositories/authz.js\";\n\nconst DOMAIN_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\\.[a-zA-Z0-9-]+)+$/;\n\n/**\n * GET - List all allowed domains\n */\nexport const GET: APIRoute = async ({ locals }) => {\n\tconst { emdash, user } = locals;\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"Database not configured\", 500);\n\t}\n\n\tconst denied = requirePerm(user, \"users:manage\");\n\tif (denied) return denied;\n\n\tconst adapter = createKyselyAdapter(emdash.db);\n\n\ttry {\n\t\tconst domains = await adapter.getAllowedDomains();\n\n\t\treturn apiSuccess({\n\t\t\tdomains: domains.map((d) => ({\n\t\t\t\tdomain: d.domain,\n\t\t\t\tdefaultRole: d.defaultRole,\n\t\t\t\tdefaultRoleId: d.defaultRoleId,\n\t\t\t\troleName: roleFromLevel(d.defaultRole),\n\t\t\t\tenabled: d.enabled,\n\t\t\t\tcreatedAt: d.createdAt.toISOString(),\n\t\t\t})),\n\t\t});\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to list allowed domains\", \"DOMAIN_LIST_ERROR\");\n\t}\n};\n\n/**\n * POST - Add a new allowed domain\n */\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"Database not configured\", 500);\n\t}\n\n\tconst denied = requirePerm(user, \"users:manage\");\n\tif (denied) return denied;\n\n\tconst adapter = createKyselyAdapter(emdash.db);\n\n\ttry {\n\t\tconst body = await parseBody(request, allowedDomainCreateBody);\n\t\tif (isParseError(body)) return body;\n\n\t\t// `defaultRoleId` (id or slug) wins; the legacy level maps to a built-in.\n\t\tlet defaultRole = body.defaultRole ?? 20;\n\t\tlet defaultRoleId: string;\n\t\tif (body.defaultRoleId !== undefined) {\n\t\t\tconst summary = await new AuthzRepository(emdash.db).getRole(body.defaultRoleId);\n\t\t\tif (!summary) return apiError(\"UNKNOWN_ROLE\", \"Role not found\", 400);\n\t\t\tdefaultRoleId = summary.id;\n\t\t\tdefaultRole = summary.level as typeof defaultRole;\n\t\t} else {\n\t\t\tdefaultRoleId = `role:${builtinRoleForLevel(defaultRole).slug}`;\n\t\t}\n\n\t\t// Validate domain format (no protocol, just domain)\n\t\tconst cleanDomain = body.domain.toLowerCase().trim();\n\t\tif (!DOMAIN_REGEX.test(cleanDomain)) {\n\t\t\treturn apiError(\"VALIDATION_ERROR\", \"Invalid domain format\", 400);\n\t\t}\n\n\t\t// Check if domain already exists\n\t\tconst existing = await adapter.getAllowedDomain(cleanDomain);\n\t\tif (existing) {\n\t\t\treturn apiError(\"CONFLICT\", \"Domain already exists\", 409);\n\t\t}\n\n\t\tconst domain = await adapter.createAllowedDomain(cleanDomain, defaultRole, defaultRoleId);\n\n\t\treturn apiSuccess(\n\t\t\t{\n\t\t\t\tsuccess: true,\n\t\t\t\tdomain: {\n\t\t\t\t\tdomain: domain.domain,\n\t\t\t\t\tdefaultRole: domain.defaultRole,\n\t\t\t\t\tdefaultRoleId: domain.defaultRoleId,\n\t\t\t\t\troleName: roleFromLevel(domain.defaultRole),\n\t\t\t\t\tenabled: domain.enabled,\n\t\t\t\t\tcreatedAt: domain.createdAt.toISOString(),\n\t\t\t\t},\n\t\t\t},\n\t\t\t201,\n\t\t);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to create allowed domain\", \"DOMAIN_CREATE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAUA,MAAa,YAAY;AAWzB,MAAM,eAAe;;;;AAKrB,MAAa,MAAgB,OAAO,EAAE,aAAa;CAClD,MAAM,EAAE,QAAQ,SAAS;AAEzB,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,2BAA2B,IAAI;CAGlE,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,UAAU,oBAAoB,OAAO,GAAG;AAE9C,KAAI;AAGH,SAAO,WAAW,EACjB,UAHe,MAAM,QAAQ,mBAAmB,EAG/B,KAAK,OAAO;GAC5B,QAAQ,EAAE;GACV,aAAa,EAAE;GACf,eAAe,EAAE;GACjB,UAAU,cAAc,EAAE,YAAY;GACtC,SAAS,EAAE;GACX,WAAW,EAAE,UAAU,aAAa;GACpC,EAAE,EACH,CAAC;UACM,OAAO;AACf,SAAO,YAAY,OAAO,kCAAkC,oBAAoB;;;;;;AAOlF,MAAa,OAAiB,OAAO,EAAE,SAAS,aAAa;CAC5D,MAAM,EAAE,QAAQ,SAAS;AAEzB,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,2BAA2B,IAAI;CAGlE,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,UAAU,oBAAoB,OAAO,GAAG;AAE9C,KAAI;EACH,MAAM,OAAO,MAAM,UAAU,SAAS,wBAAwB;AAC9D,MAAI,aAAa,KAAK,CAAE,QAAO;EAG/B,IAAI,cAAc,KAAK,eAAe;EACtC,IAAI;AACJ,MAAI,KAAK,kBAAkB,QAAW;GACrC,MAAM,UAAU,MAAM,IAAI,gBAAgB,OAAO,GAAG,CAAC,QAAQ,KAAK,cAAc;AAChF,OAAI,CAAC,QAAS,QAAO,SAAS,gBAAgB,kBAAkB,IAAI;AACpE,mBAAgB,QAAQ;AACxB,iBAAc,QAAQ;QAEtB,iBAAgB,QAAQ,oBAAoB,YAAY,CAAC;EAI1D,MAAM,cAAc,KAAK,OAAO,aAAa,CAAC,MAAM;AACpD,MAAI,CAAC,aAAa,KAAK,YAAY,CAClC,QAAO,SAAS,oBAAoB,yBAAyB,IAAI;AAKlE,MADiB,MAAM,QAAQ,iBAAiB,YAAY,CAE3D,QAAO,SAAS,YAAY,yBAAyB,IAAI;EAG1D,MAAM,SAAS,MAAM,QAAQ,oBAAoB,aAAa,aAAa,cAAc;AAEzF,SAAO,WACN;GACC,SAAS;GACT,QAAQ;IACP,QAAQ,OAAO;IACf,aAAa,OAAO;IACpB,eAAe,OAAO;IACtB,UAAU,cAAc,OAAO,YAAY;IAC3C,SAAS,OAAO;IAChB,WAAW,OAAO,UAAU,aAAa;IACzC;GACD,EACD,IACA;UACO,OAAO;AACf,SAAO,YAAY,OAAO,mCAAmC,sBAAsB"}