/** * POST /api/workspaces/[slug]/domains/[domain]/attach * * Wires a registered domain up to a Coolify app (or arbitrary IP/CNAME) * in one call. Idempotent — safe to retry. * * The heavy lifting lives in `lib/domain-attach.ts` so the MCP tool of the * same name executes the same workflow. * * Body: * { * appUuid?: string, * ip?: string, * cname?: string, * subdomains?: string[] // default ["@", "www"] * updateRegistrarNs?: boolean // default true * } */ import { NextResponse } from 'next/server'; import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth'; import { attachDomain, AttachError, type AttachInput } from '@/lib/domain-attach'; import { getDomainForWorkspace } from '@/lib/domains'; export async function POST( request: Request, { params }: { params: Promise<{ slug: string; domain: string }> }, ) { const { slug, domain: domainRaw } = await params; const principal = await requireWorkspacePrincipal(request, { targetSlug: slug }); if (principal instanceof NextResponse) return principal; const ws = principal.workspace; const apex = decodeURIComponent(domainRaw).toLowerCase().trim(); const row = await getDomainForWorkspace(ws.id, apex); if (!row) { return NextResponse.json({ error: 'Domain not found in this workspace' }, { status: 404 }); } let body: AttachInput = {}; try { body = await request.json(); } catch { // empty body is acceptable for a no-op attach check } try { const result = await attachDomain(ws, row, body); return NextResponse.json({ ok: true, domain: { id: result.domain.id, domain: result.domain.domain, dnsProvider: result.domain.dns_provider, dnsZoneId: result.domain.dns_zone_id, dnsNameservers: result.domain.dns_nameservers, }, zone: result.zone, records: result.records, registrarNsUpdate: result.registrarNsUpdate, coolifyUpdate: result.coolifyUpdate, }); } catch (err) { if (err instanceof AttachError) { return NextResponse.json( { error: err.message, tag: err.tag, ...(err.extra ?? {}) }, { status: err.status }, ); } console.error('[domains.attach] unexpected', err); return NextResponse.json( { error: 'Attach failed', details: err instanceof Error ? err.message : String(err) }, { status: 500 }, ); } }