import { createServerFn } from "@tanstack/react-start"; import { z } from "zod"; import { email } from "~/lib/validation"; import { enforceRateLimit, requestIp } from "~/server/limits"; import { requireTurnstile } from "~/server/turnstile"; import { invitedEmail, joinWaitlist, signupsFull } from "~/server/waitlist"; /** Whether the signup form should offer the waitlist instead, and who an invite link was sent to. */ export const getSignupGate = createServerFn({ method: "GET" }) .validator(z.object({ invite: z.string().max(200).optional() })) .handler(async ({ data }) => { const invited = data.invite ? await invitedEmail(data.invite) : null; return { full: await signupsFull(), invitedEmail: invited, inviteExpired: Boolean(data.invite) && !invited }; }); export const joinSignupWaitlist = createServerFn({ method: "POST" }) .validator(z.object({ email, turnstileToken: z.string().max(2048).optional() })) .handler(async ({ data }) => { await enforceRateLimit("AUTH_LIMITER", `waitlist:${requestIp()}`); await requireTurnstile(data.turnstileToken, "signup"); return { place: await joinWaitlist(data.email.toLowerCase()) }; });