File size: 1,524 Bytes
5ef6e9d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /**
* POST /api/solve
*
* Returns a valid Cloudflare Turnstile token for geminigen.ai.
* Protected by optional SOLVER_SECRET environment variable.
*
* Response: { token: string, cached: boolean, solvedInMs?: number }
* Error: { error: string }
*/
import type { VercelRequest, VercelResponse } from "@vercel/node";
import { solveTurnstile, invalidateCache } from "../src/solver";
export default async function handler(
req: VercelRequest,
res: VercelResponse
) {
// CORS preflight
if (req.method === "OPTIONS") {
return res.status(200).end();
}
if (req.method !== "POST" && req.method !== "GET") {
return res.status(405).json({ error: "Method not allowed" });
}
// Optional secret check
const secret = process.env.SOLVER_SECRET;
if (secret) {
const provided =
req.headers["x-solver-secret"] ||
req.query.secret ||
req.body?.secret;
if (provided !== secret) {
return res.status(401).json({ error: "Unauthorized" });
}
}
// Force-invalidate cached token if requested
if (req.query.force === "1" || req.body?.force) {
invalidateCache();
}
try {
console.log("[solve] Starting Turnstile solve...");
const result = await solveTurnstile();
console.log(
`[solve] Done — cached=${result.cached}, ms=${result.solvedInMs ?? 0}`
);
return res.json(result);
} catch (err: any) {
console.error("[solve] Error:", err?.message);
return res.status(500).json({ error: err?.message || "Solver failed" });
}
}
|