/** * POST /api/workspaces/[slug]/domains/search * * Checks availability + pricing for one or more candidate domains against * OpenSRS. Stateless; doesn't touch the DB. * * Body: { names: string[], period?: number } * - names: up to 25 fully-qualified names (e.g. "vibnai.com", "vibn.io") * - period: desired registration period in years (default 1). Auto-bumped * to the registry minimum for quirky TLDs (e.g. .ai = 2 yrs). */ import { NextResponse } from 'next/server'; import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth'; import { checkDomain, OpenSrsError } from '@/lib/opensrs'; const MAX_NAMES = 25; export async function POST( request: Request, { params }: { params: Promise<{ slug: string }> }, ) { const { slug } = await params; const principal = await requireWorkspacePrincipal(request, { targetSlug: slug }); if (principal instanceof NextResponse) return principal; let body: { names?: unknown; period?: unknown } = {}; try { body = await request.json(); } catch { return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 }); } const names = Array.isArray(body.names) ? (body.names as unknown[]).filter((x): x is string => typeof x === 'string' && x.trim().length > 0) : []; if (names.length === 0) { return NextResponse.json( { error: 'Body must contain { names: string[] } with at least one domain' }, { status: 400 }, ); } if (names.length > MAX_NAMES) { return NextResponse.json( { error: `Too many names (max ${MAX_NAMES})` }, { status: 400 }, ); } const period = typeof body.period === 'number' && body.period > 0 ? body.period : 1; const results = await Promise.all( names.map(async raw => { const name = raw.trim().toLowerCase().replace(/^https?:\/\//, '').replace(/\/+$/, ''); try { const r = await checkDomain(name, period); return { domain: name, available: r.available, price: r.price ?? null, currency: r.currency ?? (process.env.OPENSRS_CURRENCY ?? 'CAD'), period: r.period ?? period, responseCode: r.responseCode, responseText: r.responseText, }; } catch (err) { if (err instanceof OpenSrsError) { return { domain: name, available: false, price: null, currency: process.env.OPENSRS_CURRENCY ?? 'CAD', period, error: err.message, responseCode: err.code, }; } return { domain: name, available: false, price: null, currency: process.env.OPENSRS_CURRENCY ?? 'CAD', period, error: err instanceof Error ? err.message : String(err), }; } }), ); return NextResponse.json({ workspace: { slug: principal.workspace.slug }, mode: process.env.OPENSRS_MODE ?? 'test', results, }); }