src/app/api/admin/auth/subdomain-check/route.ts

route·app·1.9 KB · 66 lignes· Voir l'itinéraire
Annotation non disponible

Lance npm run annotate (nécessite ANTHROPIC_API_KEY dans .env.local) pour générer une annotation française par Claude Haiku 4.5.

2 exports

GETdynamic

Code source· typescript

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma/client";

export const dynamic = "force-dynamic";

const SUBDOMAIN_REGEX = /^[a-z0-9](?:[a-z0-9-]{1,28}[a-z0-9])?$/;
const RESERVED = new Set([
  "www",
  "admin",
  "api",
  "app",
  "staging",
  "blog",
  "help",
  "support",
  "dashboard",
  "mail",
  "smtp",
  "ftp",
  "ssh",
  "vpn",
  "test",
  "dev",
  "wari",
  "superadmin",
]);

// GET /api/admin/auth/subdomain-check?q=
// Check disponibilité d'un subdomain en live (debounce client-side).
// Réponse rapide pour rester < 100ms.
export async function GET(req: NextRequest) {
  const raw = (req.nextUrl.searchParams.get("q") ?? "").trim().toLowerCase();
  if (!raw) {
    return NextResponse.json({ available: false, error: "Subdomain requis" }, { status: 400 });
  }
  if (raw.length < 3) {
    return NextResponse.json({ available: false, error: "Minimum 3 caractères" });
  }
  if (raw.length > 30) {
    return NextResponse.json({ available: false, error: "Maximum 30 caractères" });
  }
  if (!SUBDOMAIN_REGEX.test(raw)) {
    return NextResponse.json({
      available: false,
      error: "Lettres minuscules, chiffres et tirets uniquement (pas de tiret en début/fin)",
    });
  }
  if (RESERVED.has(raw)) {
    return NextResponse.json({ available: false, error: "Ce nom est réservé" });
  }

  const existant = await prisma.tenant.findUnique({
    where: { subdomain: raw },
    select: { id: true, onboardingStep: true },
  });

  if (existant) {
    // Cas particulier : si c'est le tenant en cours de setup (subdomain temporaire
    // "setup-wari-..."), on accepte. Mais le subdomain de setup commence par "setup-"
    // donc ce check est rare. Pour l'instant on bloque tout subdomain pris.
    return NextResponse.json({ available: false, error: "Ce sous-domaine est déjà pris" });
  }

  return NextResponse.json({ available: true });
}