| name | edge-function-generator |
| description | Expert assistant for creating and maintaining Supabase Edge Functions for the KR92 Bible Voice project. Use when creating Edge Functions, setting up CORS, integrating shared modules, adding JWT validation, or configuring environment variables. |
Edge Function Generator
Capabilities
- Scaffold new Edge Functions with proper structure
- Set up CORS headers and error handling
- Integrate shared modules (_shared/)
- Add JWT validation and logging
- Configure environment variables
Edge Function Structure
Location
supabase/functions/
├── _shared/ # Shared modules
│ ├── ai-prompt.ts
│ ├── ai-config.ts
│ └── ai-providers.ts
├── function-name/
│ └── index.ts
Deployment
- Lovable Cloud: Auto-deploy on save
- Manual:
supabase functions deploy function-name
Usage Examples
Example 1: Create Basic Edge Function
User: "Create a new edge function to get verse of the day"
Assistant:
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
const supabase = createClient(supabaseUrl, supabaseKey);
const now = new Date();
const start = new Date(now.getFullYear(), 0, 0);
const diff = now.getTime() - start.getTime();
const dayOfYear = Math.floor(diff / (1000 * 60 * 60 * 24));
const { data: verses, error } = await supabase
.from('verses')
.select('id, text, osis, books(name_fi)')
.eq('version_id', 'finstlk201-uuid')
.limit(1)
.range(dayOfYear % 31102, dayOfYear % 31102);
if (error) throw error;
const verse = verses?.[0];
if (!verse) throw new Error('No verse found');
return new Response(
JSON.stringify({
success: true,
verse: {
text: verse.text,
reference: verse.osis,
book: verse.books?.name_fi
}
}),
{
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
status: 200,
}
);
} catch (error) {
console.error('Error:', error);
return new Response(
JSON.stringify({
success: false,
error: error.message
}),
{
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
status: 500,
}
);
}
});
Example 2: Edge Function with JWT Authentication
User: "Create edge function for user to save custom bookmark with note"
Assistant:
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
interface RequestBody {
verse_id: string;
osis: string;
note?: string;
}
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
const authHeader = req.headers.get('Authorization');
if (!authHeader) {
throw new Error('Missing authorization header');
}
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
const supabaseKey = Deno..()!;
supabase = (supabaseUrl, supabaseKey, {
: {
: { : authHeader },
},
});
{ : { user }, : userError } = supabase..();
(userError || !user) {
();
}
: = req.();
{ verse_id, osis, note } = body;
(!verse_id || !osis) {
();
}
{ : bookmark, : bookmarkError } = supabase
.()
.({
: user.,
verse_id,
osis,
})
.()
.();
(bookmarkError) bookmarkError;
noteData = ;
(note) {
{ data, : noteError } = supabase
.()
.({
: user.,
verse_id,
osis,
: note,
})
.()
.();
(noteError) noteError;
noteData = data;
}
(
.({
: ,
bookmark,
: noteData,
}),
{
: { ...corsHeaders, : },
: ,
}
);
} (error) {
.(, error);
status = error. === ? : ;
(
.({
: ,
: error.,
}),
{
: { ...corsHeaders, : },
status,
}
);
}
});
Example 3: Edge Function with AI Integration
User: "Create edge function for AI-powered verse explanation"
Assistant:
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
import { getPrompt } from '../_shared/ai-prompt.ts';
import { getFeatureConfig } from '../_shared/ai-config.ts';
import { callAIProvider } from '../_shared/ai-providers.ts';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
interface RequestBody {
verse_id: string;
osis: string;
context?: string;
}
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
const startTime = Date.now();
try {
const authHeader = req.headers.get('Authorization');
const supabaseUrl = ..()!;
supabaseKey = ..()!;
supabase = (supabaseUrl, supabaseKey, {
: { : authHeader ? { : authHeader } : {} },
});
{ : { user } } = supabase..();
: = req.();
{ verse_id, osis, context } = body;
{ : verse, : verseError } = supabase
.()
.()
.(, verse_id)
.();
(verseError) verseError;
featureConfig = (supabase, , );
(!featureConfig) {
();
}
prompt = (supabase, , {
: verse.,
: osis,
: context || ,
}, );
aiResponse = (
featureConfig.,
featureConfig.,
prompt.,
prompt.,
{
: featureConfig.?. || ,
: featureConfig.?. || ,
}
);
latencyMs = .() - startTime;
supabase.().({
: user?. || ,
: user ? : ,
: ,
: verse_id,
: osis,
: featureConfig.,
: featureConfig.,
: aiResponse..,
: aiResponse..,
: aiResponse..,
: aiResponse.,
: latencyMs,
: ,
: prompt.,
});
(
.({
: ,
: aiResponse.,
: {
: verse.,
: osis,
: verse.?.,
},
: {
: featureConfig.,
latencyMs,
: aiResponse..,
},
}),
{
: { ...corsHeaders, : },
: ,
}
);
} (error) {
.(, error);
(
.({
: ,
: error.,
}),
{
: { ...corsHeaders, : },
: ,
}
);
}
});
Edge Function Templates
Minimal Template
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
return new Response(
JSON.stringify({ success: true }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
);
} catch (error) {
return new Response(
JSON.stringify({ success: false, error: error.message }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 500 }
);
}
});
With Authentication
const { data: { user }, error: userError } = await supabase.auth.getUser();
if (userError || !user) {
throw new Error('Unauthorized');
}
With Request Validation
const body = await req.json();
const required = ['field1', 'field2'];
for (const field of required) {
if (!body[field]) {
throw new Error(`Missing required field: ${field}`);
}
}
Common Patterns
1. CORS Headers
Always include for client access:
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
2. Error Handling
try {
} catch (error) {
console.error('Error:', error);
return new Response(
JSON.stringify({ success: false, error: error.message }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 500 }
);
}
3. Supabase Client
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
const supabase = createClient(supabaseUrl, supabaseKey);
4. Environment Variables
const apiKey = Deno.env.get('EXTERNAL_API_KEY');
if (!apiKey) {
throw new Error('Missing API key configuration');
}
Deployment
Via Lovable Cloud
- Save file → auto-deploys
- View logs in Supabase Dashboard
Via CLI
supabase functions deploy function-name
Test Locally
supabase functions serve function-name
Testing Edge Functions
cURL Test
curl -X POST https://project.supabase.co/functions/v1/function-name \
-H "Authorization: Bearer YOUR_ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"key": "value"}'
TypeScript Test
const { data, error } = await supabase.functions.invoke('function-name', {
body: { key: 'value' }
});
Related Documentation
- See
Docs/02-DESIGN.md for Edge Functions overview
- See
Docs/06-AI-ARCHITECTURE.md for AI integration patterns