// /app/api/support/kofi/claim/verify/route.ts import { NextRequest, NextResponse } from "next/server"; const DIRECTUS = (process.env.DIRECTUS_URL || "").replace(/\/$/, ""); const BOT_TOKEN = process.env.DIRECTUS_TOKEN_ADMIN_SUPPORTER!; const COLLECTION = "user_memberships"; // Default redirects; can be overridden by env const SUCCESS_REDIRECT = process.env.KOFI_LINK_SUCCESS_URL || "/portal/account?linked=kofi&ok=1"; const FAIL_REDIRECT = process.env.KOFI_LINK_FAIL_URL || "/portal/account?linked=kofi&error=1"; export async function GET(req: NextRequest) { const token = req.nextUrl.searchParams.get("token") || ""; const to = (path: string) => NextResponse.redirect(new URL(path, req.url)); if (!token) return to(FAIL_REDIRECT); // Find the claim row by token const filter = encodeURIComponent(JSON.stringify({ claim_token: { _eq: token } })); const res = await fetch(`${DIRECTUS}/items/${COLLECTION}?filter=${filter}&limit=1`, { headers: { Authorization: `Bearer ${BOT_TOKEN}` }, cache: "no-store", }); if (!res.ok) return to(FAIL_REDIRECT); const json = await res.json().catch(() => ({} as any)); const rec = json?.data?.[0]; if (!rec) return to(FAIL_REDIRECT); // Validate expiry and sanity const exp = rec.claim_expires_at ? new Date(rec.claim_expires_at).getTime() : 0; if (!exp || Date.now() > exp) return to(FAIL_REDIRECT); if (!rec.claim_user_id) return to(FAIL_REDIRECT); // Finalize: set app_user to claim_user_id; clear claim fields const patch = await fetch(`${DIRECTUS}/items/${COLLECTION}/${rec.id}`, { method: "PATCH", headers: { "Content-Type": "application/json", Authorization: `Bearer ${BOT_TOKEN}`, }, body: JSON.stringify({ app_user: rec.claim_user_id, claim_token: null, claim_expires_at: null, claim_user_id: null, last_event_at: new Date().toISOString(), }), }); if (!patch.ok) return to(FAIL_REDIRECT); return to(SUCCESS_REDIRECT); }