## Demo: captcha ### Captcha.svelte ```svelte

mintCaptcha() seals a single-use token at SSR. Sliding the handle advances a hash chain one link per step, then solves a proof-of-work over the final link — so the challenge only exists once the slide has actually run, and never appears in the page. verifyCaptcha() re-derives it server-side.

The submit button is not gated on the captcha here, so you can submit without solving it and watch the server reject you.

Submit twice (replay) verifies the same token twice in one action — the first call burns the nonce, so the second is a real replay. A failure carries a reason, shown under each message: solve the captcha first and you get replay, which the demo answers with its own copy. Leave it unsolved and every probe-able failure — tampered, too fast, expired, bad proof-of-work — collapses to rejected behind one generic message, so a bot can't tell them apart.

``` ### CaptchaForm.svelte ```svelte {#if sentMessage}

✅ {sentMessage}

Reload for a fresh challenge
{:else}
{#if errorMessage} {/if}
{/if} ``` ### routes.ts ```ts import { Mochi, fail, success, mintCaptcha, verifyCaptcha } from 'mochi-framework'; import type { MochiRouteValue } from 'mochi-framework'; export const routes: Record = { '/demos/captcha': Mochi.page('./src/demos/captcha/Captcha.svelte', { serverProps: () => ({ captcha: mintCaptcha() }), actions: { submit: async ({ formData }) => { const captcha = await verifyCaptcha(formData); if (!captcha.ok) { return fail(400, { error: captcha.error, reason: captcha.reason }); } const name = String(formData.get('name') ?? '').trim(); return success({ message: `Verified — nice to meet you, ${name || 'stranger'}.` }); }, // Verifies the same token twice: the first call burns the nonce, so the // second is a genuine replay rather than a faked message. Lets one click // reach the `reason === 'replay'` branch without solving two captchas. // An unsolved token fails both calls and lands on 'rejected' instead, // which is the other half of what this demonstrates. replay: async ({ formData }) => { await verifyCaptcha(formData); const captcha = await verifyCaptcha(formData); if (!captcha.ok) { return fail(400, { error: captcha.reason === 'replay' ? 'Our own copy: that token is spent — reload for a fresh challenge.' : captcha.error, reason: captcha.reason, }); } return success({ message: 'Unexpected — the nonce survived a double verify.' }); }, }, }), }; ``` ### index.ts ```ts import { Mochi, logger } from 'mochi-framework'; import { routes } from './routes'; await Mochi.serve({ port: 3333, development: process.env.MODE === 'development', routes, }); logger.info('Server running at http://localhost:3333'); ```