Appearance
Adding an Edge Function
1. Decide the type
| Type A | Type B | |
|---|---|---|
| Use when | client-triggered write/secret/external-HTTP | cron / internal / webhook |
| Auth | requireAuth(req) | deployed --no-verify-jwt |
| Name | domain-action | domain-noun-verb |
2. Scaffold
Create supabase/functions/<name>/ with index.ts, helpers.ts, and tests/. Follow the shared entrypoint pattern:
ts
const preflight = handleCors(req); if (preflight) return preflight; // 1
try {
const { user, serviceClient } = await requireAuth(req); // 2 (Type A)
const body = await req.json();
if (!body.required) throw new ValidationError('required is required.'); // 3
// 4 business logic — complex parts in helpers.ts
return ok({ result }); // 5
} catch (e) { return err('<name>', e); } // 6- Use
ok()/err()from_shared/response.tsfor all responses. - Throw typed errors (
ValidationError,ForbiddenError,NotFoundError,ConflictError) for status-safe responses. - Log with
_shared/logger.ts; INFO/WARN logs must carry aneventfield. - Read secrets via
Deno.env.get()— never log them.
3. Webhooks & idempotency
If receiving a webhook, verify the HMAC signature with a timestamp replay window + constant-time compare, and record each delivery in an audit table with a UNIQUE event id (mirror finfluencify-stream-webhook).
4. Register the name
Add it to the feature's EDGE_FN config map (e.g. edgeBuilderConfig.js). Never inline the string in a service.
5. Tests (before deploy)
Co-locate tests/. Cover: success paths, validation failures, auth/ownership (typed errors), safe 500s, and webhook signature/idempotency where relevant. Run npm run test:ef (or a targeted Deno command).
6. Document & regenerate
Re-run npm run docs:gen so the EF index picks it up. Add a dedicated page from backend/edge-functions/_template if it warrants one, and a row in Environment Variables for any new secret.
Templates + security checklist: documentations/claude/EF_PATTERNS.md and documentations/01-layout/guidelines/supabase-edge-functions-guidelines.md.