import { NextResponse } from "next/server"; import { createCart, getCart } from "@/lib/medusa"; import { headers } from "next/headers"; import { createRateLimiter, getClientIp } from "@/lib/rateLimit"; import { isNonEmptyString, checkCsrf, isValidMedusaId, badRequest } from "@/lib/apiUtils"; import { getAuthToken } from "@/lib/auth"; // 10 cart creations per IP per 15 minutes const limiter = createRateLimiter({ windowMs: 15 * 60 * 1000, maxRequests: 10 }); // POST /api/cart — create a new cart export async function POST() { const csrfError = await checkCsrf(); if (csrfError) return csrfError; const hdrs = await headers(); const ip = getClientIp(hdrs); const limit = limiter.check(`cart:${ip}`); if (!limit.allowed) { return NextResponse.json( { error: "Too many requests. Please try again later." }, { status: 429, headers: { "Retry-After": String(Math.ceil(limit.retryAfterMs / 1000)) } }, ); } // Pass auth token so Medusa associates the cart with the logged-in customer const authToken = (await getAuthToken()) ?? undefined; try { const cart = await createCart(authToken); return NextResponse.json(cart); } catch (e) { console.error("[cart:create]", (e as Error).message); return NextResponse.json({ error: "Failed to create cart" }, { status: 500 }); } } // GET /api/cart?id=cart_xxx — fetch an existing cart export async function GET(request: Request) { const { searchParams } = new URL(request.url); const id = searchParams.get("id"); if (!isNonEmptyString(id)) { return badRequest("Missing cart id"); } if (!isValidMedusaId(id)) { return badRequest("Invalid cart ID format"); } try { const cart = await getCart(id); if (!cart) { return NextResponse.json({ error: "Cart not found" }, { status: 404 }); } return NextResponse.json(cart); } catch (e) { console.error("[cart:get]", (e as Error).message); return NextResponse.json({ error: "Failed to fetch cart" }, { status: 500 }); } }