// Setup type definitions for built-in Supabase Runtime APIs import "@supabase/functions-js/edge-runtime.d.ts"; import { corsHeaders } from "../_shared/cors.ts"; import { OpenAIService } from "../_shared/openai-service.ts"; import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; type WebhookPayload = { type: "INSERT" | "UPDATE" | "DELETE"; table: string; schema: string; record: Record | null; old_record: Record | null; }; const SUPABASE_URL = Deno.env.get("SUPABASE_URL") ?? ""; const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? ""; const ALLOWED_SCHEMA = "public"; const ALLOWED_TABLES = new Set(["planes_estudio", "asignaturas"]); const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, { auth: { persistSession: false }, }); function jsonResponse(status: number, body: Record) { return new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json", ...corsHeaders }, }); } async function createConversationId( openaiService: OpenAIService, metadata: Record, ) { const conversation = await openaiService.createConversation(metadata); const conversationId = conversation?.id as string | undefined; if (!conversationId) { throw new Error("OpenAI response missing conversation id"); } return conversationId; } Deno.serve(async (req) => { if (req.method !== "POST") { return jsonResponse(405, { error: "Method not allowed" }); } if (!SUPABASE_URL || !SUPABASE_SERVICE_ROLE_KEY) { return jsonResponse(500, { error: "Supabase env vars missing" }); } const openaiService = OpenAIService.fromEnv(); if (!(openaiService instanceof OpenAIService)) { return jsonResponse(500, { error: openaiService.message }); } let payload: WebhookPayload; try { payload = await req.json(); } catch { return jsonResponse(400, { error: "Invalid JSON body" }); } const { type, table, schema, record } = payload; if (schema !== ALLOWED_SCHEMA || !ALLOWED_TABLES.has(table)) { return jsonResponse(400, { error: "Table not allowed" }); } if (type !== "INSERT") { return jsonResponse(200, { status: "ignored", reason: "event_type" }); } if (!record || typeof record !== "object") { return jsonResponse(400, { error: "Missing record" }); } const recordId = record["id"] as string | number | undefined; if (!recordId) { return jsonResponse(400, { error: "Record id missing" }); } const existingConversationId = record["conversation_id"] as | string | null | undefined; if (existingConversationId) { return jsonResponse(200, { status: "skipped", conversation_id: existingConversationId, }); } let conversationId: string; try { conversationId = await createConversationId(openaiService, { table, record_id: String(recordId), }); } catch (error) { return jsonResponse(502, { error: (error as Error).message }); } const { error } = await supabase .from(table) .update({ conversation_id: conversationId }) .eq("id", recordId); if (error) { return jsonResponse(500, { error: error.message }); } return jsonResponse(200, { status: "updated", table, record_id: recordId, conversation_id: conversationId, }); });