Scaffold a new Supabase Deno edge function following SmartATS conventions. Trigger when the user says "create edge function", "add a new function", "new edge function for X", or "scaffold function".
Ask if not provided. Must be kebab-case (e.g. score-resume, send-notification).
Path: supabase/functions/<name>/index.ts
/**
* UPDATE LOG
* YYYY-MM-DD HH:MM:SS | Created — <one-line description of what this function does>
*/
import 'https://deno.land/x/[email protected]/mod.ts'
import { serve } from 'https://deno.land/[email protected]/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
import { isOriginAllowed, buildCorsHeaders } from '../_shared/cors.ts'
import { getEnvNumber, getEnvBoolean } from '../_shared/env.ts'
import { callLLM, type LLMRequest } from '../_shared/llmProvider.ts'
// --- Env var validation (fail fast at startup, not at request time) ---
const OPENAI_API_KEY = Deno.env.get('OPENAI_API_KEY')
const SUPABASE_URL = Deno.env.get('SUPABASE_URL')
const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
serve(async (req: Request) => {
const origin = req.headers.get('origin')
// OPTIONS preflight
if (req.method === 'OPTIONS') {
return new Response(null, { headers: buildCorsHeaders(origin) })
}
// Config guard — return 503 (not 500) for missing env vars
if (!OPENAI_API_KEY || !SUPABASE_URL || !SUPABASE_SERVICE_ROLE_KEY) {
return new Response(JSON.stringify({ error: 'Service misconfigured' }), {
status: 503,
headers: { ...buildCorsHeaders(origin), 'Content-Type': 'application/json' },
})
}
// CORS origin check
if (!isOriginAllowed(origin)) {
return new Response(JSON.stringify({ error: 'Origin not allowed' }), {
status: 403,
headers: { ...buildCorsHeaders(origin), 'Content-Type': 'application/json' },
})
}
try {
// Parse request body
const body = await req.json()
// TODO: validate required fields from body
// Supabase client (authenticated with user JWT for RLS)
const authHeader = req.headers.get('Authorization') ?? ''
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, {
global: { headers: { Authorization: authHeader } },
})
// TODO: main logic — DB queries, callLLM(), etc.
return new Response(JSON.stringify({ success: true }), {
status: 200,
headers: { ...buildCorsHeaders(origin), 'Content-Type': 'application/json' },
})
} catch (err) {
const message = err instanceof Error ? err.message : 'Unexpected error'
return new Response(JSON.stringify({ error: message }), {
status: 500,
headers: { ...buildCorsHeaders(origin), 'Content-Type': 'application/json' },
})
} finally {
// Telemetry — must never block or propagate errors to callers
try {
// await logEvent(...)
} catch {
// swallow telemetry errors
}
}
})
Output these follow-up steps:
TODO sections with the function's actual logicmigration-writer agent firstsupabase functions serve <name>supabase functions deploy <name>supabase/config.tomlfetch('https://api.openai.com/...') calls — always use callLLM()buildCorsHeaders(origin)503 for missing/invalid env vars, not 500logEvent() / centralized-logging calls inside their own try/catch