import type { Context } from "@wrnexus/core"; import type { CaptchaEngine, CaptchaProvider, CaptchaVerificationResult, VerifyCaptchaInput, } from "./types.ts"; import { selfHostedProvider } from "./providers/self-hosted.ts"; export function captchaTokenFrom( value: Request | Headers | FormData | URLSearchParams | Record, field = "wrn-captcha-response", ): Promise | string | undefined { if (value instanceof Request) { const header = value.headers.get("x-wrn-captcha-token"); if (header) return header; return value .clone() .formData() .then((form) => { const token = form.get(field) ?? form.get("captchaToken") ?? form.get("responseToken"); return typeof token === "string" ? token : undefined; }) .catch(async () => { try { const body = (await value.clone().json()) as Record; const token = body[field] ?? body.captchaToken ?? body.responseToken; return token === undefined ? undefined : String(token); } catch { return undefined; } }); } if (value instanceof Headers) { return value.get("x-wrn-captcha-token") ?? value.get("x-captcha-token") ?? undefined; } if (value instanceof FormData || value instanceof URLSearchParams) { const token = value.get(field) ?? value.get("captchaToken") ?? value.get("responseToken"); return typeof token === "string" ? token : undefined; } const token = value[field] ?? value.captchaToken ?? value.responseToken; return token === undefined ? undefined : String(token); } export function captchaHeaders(token: string): HeadersInit { return { "x-wrn-captcha-token": token }; } export function captchaFields( token: string, field = "wrn-captcha-response", ): Record { return { [field]: token }; } export async function verifyCaptcha( providerOrEngine: CaptchaProvider | CaptchaEngine, input: VerifyCaptchaInput, ): Promise { const provider: CaptchaProvider = "client" in providerOrEngine ? (providerOrEngine as CaptchaProvider) : selfHostedProvider(providerOrEngine as CaptchaEngine); return provider.verify(input); } export async function verifyCaptchaOrThrow( providerOrEngine: CaptchaProvider | CaptchaEngine, input: VerifyCaptchaInput, ): Promise { const result = await verifyCaptcha(providerOrEngine, input); if (!result.success) { throw new Error( `WRN-CAPTCHA-${String(result.code ?? "FAILED").toUpperCase()}: ${result.message ?? "CAPTCHA verification failed"}`, ); } return result; } export function captchaResultResponse(result: CaptchaVerificationResult): Response { return Response.json(result, { status: result.success ? 200 : 403, headers: { "cache-control": "no-store", "x-content-type-options": "nosniff" }, }); } export function captchaContext(ctx: Context): CaptchaVerificationResult | null { const result = ctx.locals.captcha; return result && typeof result === "object" ? (result as CaptchaVerificationResult) : null; }