| name | edge-function-generator |
| description | Expert assistant for creating and maintaining Supabase Edge Functions for the KR92 Bible Voice project. Use when (1) creating new Edge Functions, (2) setting up CORS and error handling, (3) integrating shared modules from _shared/, (4) adding JWT validation, (5) configuring environment variables, (6) auditing or updating dependency versions across functions. Triggers include "edge function", "create function", "serverless", "deno function", "update edge imports", "version drift". |
Edge Function Generator
Skill-specific learnings: See references/learnings.md for error-handling and deployment gotchas (Postgrest catch-block masking, auto-deploy workflow since 2026-05-22).
Context Files
Read from Docs/context/ for project-specific patterns:
supabase-map.md - Edge Functions list and structure
db-schema-short.md - Database tables for queries
Centralized Dependencies
All Edge Functions import from _shared/deps.ts - never use direct URLs:
import { serve, createClient, corsHeaders, crypto } from "../_shared/deps.ts";
The deps.ts module centralizes all versions (deno std@0.190.0, supabase-js@2.49.1) and includes the XHR polyfill as a side-effect import. See references/versions.md for rationale and Docs/ops/edge-deps-standardization.md for upgrade instructions.
Edge Function Structure
supabase/functions/
├── _shared/ # Shared modules (import with ../_shared/)
│ ├── deps.ts # Centralized dependencies - import from here!
│ ├── ai-config.ts
│ ├── ai-prompt.ts
│ ├── ai-providers.ts
│ └── ai-quota.ts
├── function-name/
│ └── index.ts
Minimal Template
import { corsHeaders, createClient, serve } from "../_shared/deps.ts";
serve(async (req) => {
if (req.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}
try {
const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
const supabaseKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
const supabase = createClient(supabaseUrl, supabaseKey);
return new Response(
JSON.stringify({ success: true }),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{ headers: { ...corsHeaders, "Content-Type": "application/json" }, status: 500 }
);
}
});
With JWT Authentication
const authHeader = req.headers.get("Authorization");
if (!authHeader) {
return new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 401,
headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
const supabase = createClient(supabaseUrl, supabaseAnonKey, {
global: { headers: { Authorization: authHeader } },
});
const { data: { user }, error: authError } = await supabase.auth.getUser();
if (authError || !user) {
return new Response(JSON.stringify({ error: "Invalid token" }), {
status: 401,
headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
With AI Integration
import { corsHeaders, createClient, serve } from "../_shared/deps.ts";
import { getFeatureConfig } from "../_shared/ai-config.ts";
import { getPrompt } from "../_shared/ai-prompt.ts";
import { callProvider } from "../_shared/ai-providers.ts";
import { enforceQuotaOrThrow } from "../_shared/ai-quota.ts";
await enforceQuotaOrThrow(featureKey, estimatedTokens, userId);
const config = await getFeatureConfig(featureKey, "prod");
const prompt = await getPrompt(featureKey, variables, "prod");
const response = await callProvider({
vendor: config.vendor,
model: config.model,
systemPrompt: prompt.systemPrompt,
userPrompt: prompt.userPrompt,
params: config.params,
});
Version Audit Workflow
When auditing for stray direct imports:
grep -r "deno.land/std@" supabase/functions/ | grep -v deps.ts
grep -r "esm.sh/@supabase" supabase/functions/ | grep -v deps.ts
If any function has direct imports, update it to use ../\_shared/deps.ts instead. See references/versions.md for version rationale.
Deployment
supabase functions deploy function-name
mcp__supabase__deploy_edge_function
Testing
supabase functions serve function-name
curl -X POST https://PROJECT.supabase.co/functions/v1/function-name \
-H "Authorization: Bearer ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"key": "value"}'