import type { AppContext } from "@/worker/hono"; import { HttpError } from "@/worker/http"; export type SocialProvider = "github" | "google"; interface ClientConfigResponse { turnstileSiteKey: string; issuer: string; socialProviders: SocialProvider[]; operatorName: string; operatorContactEmail: string; } // /api/config gates the public Turnstile site key the React app needs to // render the widget. A missing TURNSTILE_SITE_KEY is a deployment error, // not a runtime feature toggle — the verifier already fails closed on a // missing TURNSTILE_SECRET_KEY (services/turnstile.ts), and surfacing 503 // here lets the sign-in / invite-accept pages show an actionable error // instead of an indefinite "Loading verification..." state. // // Also advertises the OIDC issuer (so the landing-page metadata reflects // the actual deployment instead of hardcoding a host), the list of // configured social providers (so the UI only renders buttons that can // successfully complete the flow), and the operator identity rendered on // /privacy and /terms (so the same React build can serve different // deployments without hardcoding a brand name). Providers require BOTH // client id AND client secret to count as configured; a half-configured // provider would fail at the IdP round-trip. export const handleConfig = (c: AppContext): Response => { const siteKey = c.env.TURNSTILE_SITE_KEY?.trim(); if (!siteKey) { throw new HttpError(503, "turnstile_unavailable", "Human verification is not configured on this server."); } const operatorName = c.env.OPERATOR_NAME?.trim(); const operatorContactEmail = c.env.OPERATOR_CONTACT_EMAIL?.trim(); if (!operatorName || !operatorContactEmail) { throw new HttpError(503, "operator_unconfigured", "Operator identity is not configured on this server."); } const socialProviders: SocialProvider[] = []; if (c.env.GITHUB_OAUTH_CLIENT_ID?.trim() && c.env.GITHUB_OAUTH_CLIENT_SECRET?.trim()) { socialProviders.push("github"); } if (c.env.GOOGLE_OAUTH_CLIENT_ID?.trim() && c.env.GOOGLE_OAUTH_CLIENT_SECRET?.trim()) { socialProviders.push("google"); } const response: ClientConfigResponse = { turnstileSiteKey: siteKey, issuer: c.var.issuer, socialProviders, operatorName, operatorContactEmail, }; return c.json(response); };