mirror of
https://github.com/supabase/supabase.git
synced 2026-06-22 00:02:50 +08:00
## What Migrates the Edge Functions **documentation** from the legacy `Deno.serve` + manual `createClient` pattern to the [`@supabase/server`](https://github.com/supabase/server) `withSupabase` wrapper. This is the part of [COM-269](https://linear.app/supabase/issue/COM-269) that AI coding assistants index, so it's split out to ship first; the standalone `examples/` functions follow in a second PR. ## Canonical pattern ```ts import { withSupabase } from 'npm:@supabase/server@1' export default { fetch: withSupabase({ auth: 'user' }, async (req, ctx) => { const { data } = await ctx.supabase.from('countries').select('*') return Response.json({ data }) }), } ``` - `export default { fetch }` object shape (not `Deno.serve`, not a bare default export), versioned `npm:@supabase/server@1`. - `auth` mode picks the caller: `user` → `ctx.supabase` (RLS); `secret`/`publishable`/`none` → set `verify_jwt = false`, `secret` uses `ctx.supabaseAdmin`. - `Response.json(...)` over `new Response(JSON.stringify(...))`. ## Changes - **AI prompt** (`examples/prompts/edge-functions.md`) — rewritten to lead with `withSupabase` as the default; `auth`-mode table; `@supabase/server@1`. Highest AI-indexing impact. - **connect-to-postgres** — "Using supabase-js" now uses `ctx.supabase` (+ its CodeSample deps `postgres-on-the-edge`, `drizzle`). - **Example pages** — semantic-search, push-notifications, amazon-bedrock, cloudflare-turnstile, og-image, send-emails, slack-bot-mention, auth-send-email-hook. - **Guides** — ai-models, background-tasks, routing (+ `restful-tasks` dep), kysely-postgres, sentry-monitoring, upstash-redis, elevenlabs ×2, websockets, cors (reframed: CORS is automatic with `withSupabase`). ## Notable fixes - **websockets**: the JWT-auth examples had a latent bug — handler wasn't `async` and called `getClaims()` without the extracted token. Now `await supabase.auth.getUser(jwt)`. (`withSupabase` can't authenticate WebSocket clients since they can't send headers — noted in the page.) - **restful-tasks**: fixed a broken `npm:supabase-js` import → `npm:@supabase/supabase-js`. ## Follow-ups (not in this PR) - The ~42 standalone `examples/` edge functions → second PR. - A dedicated `withSupabase` intro page (today it's only documented inside the auth-framed "Securing Edge Functions" page). - `.claude/skills/supabase-server/SKILL.md` is stale (`allow:` vs `auth:`). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated Edge Function examples to the modern withSupabase + exported fetch handler pattern across guides and examples. * Standardized JSON response/error handling (uses built-in JSON helpers) and preserved streaming/SSE behaviors where applicable. * Clarified auth modes, context clients (user vs admin), and automatic CORS handling; removed manual preflight boilerplate. * Updated local serve/deploy instructions to include --no-verify-jwt for relevant examples. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
80 lines
2.3 KiB
Plaintext
80 lines
2.3 KiB
Plaintext
---
|
|
id: 'examples-cloudflare-turnstile'
|
|
title: 'CAPTCHA support with Cloudflare Turnstile'
|
|
description: 'Protecting Forms with Cloudflare Turnstile.'
|
|
tocVideo: 'OwW0znboh60'
|
|
---
|
|
|
|
[Cloudflare Turnstile](https://www.cloudflare.com/application-services/products/turnstile/) is a friendly, free CAPTCHA replacement, and it works seamlessly with Supabase Edge Functions to protect your forms. [View on GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/cloudflare-turnstile).
|
|
|
|
## Setup
|
|
|
|
- Follow these steps to set up a new site: https://developers.cloudflare.com/turnstile/get-started/
|
|
- Add the Cloudflare Turnstile widget to your site: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/
|
|
|
|
## Code
|
|
|
|
Create a new function in your project:
|
|
|
|
```bash
|
|
supabase functions new cloudflare-turnstile
|
|
```
|
|
|
|
And add the code to the `index.ts` file:
|
|
|
|
```ts index.ts
|
|
import { withSupabase } from 'npm:@supabase/server@^1'
|
|
|
|
console.log('Hello from Cloudflare Trunstile!')
|
|
|
|
function ips(req: Request) {
|
|
return req.headers.get('x-forwarded-for')?.split(/\s*,\s*/)
|
|
}
|
|
|
|
// `withSupabase` handles CORS and preflight requests for you.
|
|
export default {
|
|
fetch: withSupabase({ auth: 'none' }, async (req) => {
|
|
const { token } = await req.json()
|
|
const clientIps = ips(req) || ['']
|
|
const ip = clientIps[0]
|
|
|
|
// Validate the token by calling the
|
|
// "/siteverify" API endpoint.
|
|
let formData = new FormData()
|
|
formData.append('secret', Deno.env.get('CLOUDFLARE_SECRET_KEY') ?? '')
|
|
formData.append('response', token)
|
|
formData.append('remoteip', ip)
|
|
|
|
const url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'
|
|
const result = await fetch(url, {
|
|
body: formData,
|
|
method: 'POST',
|
|
})
|
|
|
|
const outcome = await result.json()
|
|
console.log(outcome)
|
|
if (outcome.success) {
|
|
return new Response('success')
|
|
}
|
|
return new Response('failure')
|
|
}),
|
|
}
|
|
```
|
|
|
|
## Deploy the server-side validation Edge Functions
|
|
|
|
- https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
|
|
|
|
```bash
|
|
supabase functions deploy cloudflare-turnstile --no-verify-jwt
|
|
supabase secrets set CLOUDFLARE_SECRET_KEY=your_secret_key
|
|
```
|
|
|
|
## Invoke the function from your site
|
|
|
|
```js
|
|
const { data, error } = await supabase.functions.invoke('cloudflare-turnstile', {
|
|
body: { token },
|
|
})
|
|
```
|