import { NextResponse } from "next/server"; import { getActiveProducts } from "@/lib/data"; import { formatPrice } from "@/lib/format"; import { rateLimit, getClientIp } from "@/lib/rate-limit"; import { getLocale } from "@/i18n/locale"; const SUGGESTION_LIMIT = 5; const SUGGEST_ATTEMPTS_PER_WINDOW = 60; const SUGGEST_WINDOW_MS = 60 * 1000; /** * Liefert bis zu 5 passende Produkte fuer die Live-Suchvorschlaege im * Header — dieselbe Suchlogik wie die Shop-Uebersicht (getActiveProducts), * nur ohne vollen Seiten-Reload. Rein oeffentliche, bereits im Shop * sichtbare Produktdaten, keine Authentifizierung noetig, aber wie jeder * andere oeffentliche Endpunkt hier rate-limitiert (grosszuegig, da bei * jedem Tastenanschlag aufgerufen). */ export async function GET(request: Request) { const ip = await getClientIp(); if (!rateLimit(`search-suggest:${ip}`, SUGGEST_ATTEMPTS_PER_WINDOW, SUGGEST_WINDOW_MS)) { return NextResponse.json({ suggestions: [] }, { status: 429 }); } const query = new URL(request.url).searchParams.get("q")?.trim() ?? ""; if (query.length < 2) { return NextResponse.json({ suggestions: [] }); } const locale = await getLocale(); const products = await getActiveProducts({ query, onlyAvailable: true }); const suggestions = products.slice(0, SUGGESTION_LIMIT).map((product) => ({ slug: product.slug, name: product.name, price: formatPrice(product.priceCents, product.currency, locale), })); return NextResponse.json({ suggestions }); }