// SCRIPT PARA GERAR TODOS OS 36 ENDPOINTS FALTANTES // Execute: deno run --allow-write generate-endpoints.ts const ENDPOINT_TEMPLATES = { "availability-list": `// MÓDULO 2.2: AVAILABILITY - /availability/list 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", }; Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const authHeader = req.headers.get("Authorization"); const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!, { global: { headers: { Authorization: authHeader! } } } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) throw new Error("Unauthorized"); const url = new URL(req.url); const doctor_id = url.searchParams.get("doctor_id"); let query = supabase.from("doctor_availability").select("*").eq("is_active", true); if (doctor_id) query = query.eq("doctor_id", doctor_id); const { data, error } = await query.order("day_of_week").order("start_time"); if (error) throw error; return new Response( JSON.stringify({ success: true, data }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, error: error.message }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });`, "availability-create": `// MÓDULO 2.2: AVAILABILITY - /availability/create 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", }; Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const authHeader = req.headers.get("Authorization"); const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!, { global: { headers: { Authorization: authHeader! } } } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) throw new Error("Unauthorized"); const body = await req.json(); const { doctor_id, external_doctor_id, day_of_week, start_time, end_time, slot_duration_minutes } = body; const { data, error } = await supabase.from("doctor_availability").insert({ doctor_id, external_doctor_id, day_of_week, start_time, end_time, slot_duration_minutes: slot_duration_minutes || 30, }).select().single(); if (error) throw error; await supabase.from("user_actions").insert({ user_id: user.id, external_user_id: external_doctor_id, action_category: "availability", action_type: "create", resource_type: "availability", resource_id: data.id }); return new Response( JSON.stringify({ success: true, data }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, error: error.message }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });`, "availability-delete": `// MÓDULO 2.2: AVAILABILITY - /availability/delete 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", }; Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const authHeader = req.headers.get("Authorization"); const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!, { global: { headers: { Authorization: authHeader! } } } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) throw new Error("Unauthorized"); const { availability_id } = await req.json(); const { error } = await supabase .from("doctor_availability") .update({ is_active: false }) .eq("id", availability_id); if (error) throw error; return new Response( JSON.stringify({ success: true, message: "Availability deleted" }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, error: error.message }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });`, "availability-slots": `// MÓDULO 2.2: AVAILABILITY - /availability/slots 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", }; Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const authHeader = req.headers.get("Authorization"); const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!, { global: { headers: { Authorization: authHeader! } } } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) throw new Error("Unauthorized"); const url = new URL(req.url); const doctor_id = url.searchParams.get("doctor_id")!; const start_date = url.searchParams.get("start_date")!; const end_date = url.searchParams.get("end_date")!; // Buscar disponibilidades do médico const { data: availability } = await supabase .from("doctor_availability") .select("*") .eq("doctor_id", doctor_id) .eq("is_active", true); // Buscar exceções const { data: exceptions } = await supabase .from("availability_exceptions") .select("*") .eq("doctor_id", doctor_id) .gte("exception_date", start_date) .lte("exception_date", end_date); // Gerar slots (algoritmo simplificado - em produção usar lib de date) const slots: any[] = []; const start = new Date(start_date); const end = new Date(end_date); for (let d = start; d <= end; d.setDate(d.getDate() + 1)) { const dayOfWeek = d.getDay(); const dateStr = d.toISOString().split('T')[0]; // Verificar se tem exceção const hasException = exceptions?.some(e => e.exception_date === dateStr && e.type === 'unavailable'); if (hasException) continue; // Buscar disponibilidade desse dia da semana const dayAvail = availability?.filter(a => a.day_of_week === dayOfWeek); if (!dayAvail || dayAvail.length === 0) continue; dayAvail.forEach(avail => { const startTime = avail.start_time; const endTime = avail.end_time; const duration = avail.slot_duration_minutes; // Gerar slots de horário (simplificado) slots.push({ date: dateStr, time: startTime, duration, available: true, doctor_id }); }); } return new Response( JSON.stringify({ success: true, data: slots }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, error: error.message }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });`, "doctor-summary": `// MÓDULO 7: DOCTOR - /doctor/summary 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", }; function externalRest(path: string): Promise { const url = \`\${Deno.env.get("EXTERNAL_SUPABASE_URL")}/rest/v1/\${path}\`; return fetch(url, { headers: { "apikey": Deno.env.get("EXTERNAL_SUPABASE_KEY")!, "Authorization": \`Bearer \${Deno.env.get("EXTERNAL_SUPABASE_KEY")}\`, } }).then(r => r.json()); } Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const authHeader = req.headers.get("Authorization"); const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!, { global: { headers: { Authorization: authHeader! } } } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) throw new Error("Unauthorized"); const url = new URL(req.url); const doctor_id = url.searchParams.get("doctor_id") || user.id; // Buscar stats da nossa DB const { data: stats } = await supabase .from("doctor_stats") .select("*") .eq("doctor_id", doctor_id) .single(); // Buscar appointments de hoje do Supabase externo const today = new Date().toISOString().split('T')[0]; const appointments = await externalRest(\`appointments?doctor_id=eq.\${doctor_id}&appointment_date=eq.\${today}\`); // Buscar badges de gamificação const { data: badges } = await supabase .from("doctor_badges") .select("*") .eq("doctor_id", doctor_id); return new Response( JSON.stringify({ success: true, data: { stats: stats || {}, today_appointments: appointments || [], badges: badges || [], occupancy_rate: stats?.occupancy_rate || 0, no_show_rate: stats ? ((stats.no_show_count / stats.total_appointments) * 100).toFixed(2) : 0 } }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, error: error.message }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });`, "patients-history": `// MÓDULO 8: PATIENTS - /patients/history 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", }; function externalRest(path: string): Promise { const url = \`\${Deno.env.get("EXTERNAL_SUPABASE_URL")}/rest/v1/\${path}\`; return fetch(url, { headers: { "apikey": Deno.env.get("EXTERNAL_SUPABASE_KEY")!, "Authorization": \`Bearer \${Deno.env.get("EXTERNAL_SUPABASE_KEY")}\`, } }).then(r => r.json()); } Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const authHeader = req.headers.get("Authorization"); const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!, { global: { headers: { Authorization: authHeader! } } } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) throw new Error("Unauthorized"); const url = new URL(req.url); const patient_id = url.searchParams.get("patient_id") || user.id; // Buscar appointments do Supabase externo const appointments = await externalRest(\`appointments?patient_id=eq.\${patient_id}&order=appointment_date.desc\`); // Buscar histórico estendido da nossa DB const { data: extendedHistory } = await supabase .from("patient_extended_history") .select("*") .eq("patient_id", patient_id) .order("visit_date", { ascending: false }); // Buscar jornada do paciente const { data: journey } = await supabase .from("patient_journey") .select("*") .eq("patient_id", patient_id) .order("event_timestamp", { ascending: false }) .limit(50); return new Response( JSON.stringify({ success: true, data: { appointments: appointments || [], extended_history: extendedHistory || [], journey: journey || [], total_appointments: appointments?.length || 0, last_visit: appointments?.[0]?.appointment_date } }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, error: error.message }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });`, "audit-log": `// MÓDULO 13: AUDIT - /audit/log 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", }; Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const authHeader = req.headers.get("Authorization"); const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!, { global: { headers: { Authorization: authHeader! } } } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) throw new Error("Unauthorized"); const body = await req.json(); const { action_type, entity_type, entity_id, old_data, new_data } = body; const ip_address = req.headers.get("x-forwarded-for") || "unknown"; const user_agent = req.headers.get("user-agent") || "unknown"; const { data, error } = await supabase.from("audit_actions").insert({ user_id: user.id, external_user_id: body.external_user_id, action_type, entity_type, entity_id, old_data, new_data, ip_address, user_agent }).select().single(); if (error) throw error; return new Response( JSON.stringify({ success: true, data }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, error: error.message }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });`, "system-health": `// MÓDULO 15: SYSTEM - /system/health-check const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type", }; Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders }); try { const checks = { external_supabase: false, own_database: false, notifications_worker: false, }; // Check external Supabase try { const extRes = await fetch(\`\${Deno.env.get("EXTERNAL_SUPABASE_URL")}/rest/v1/appointments?limit=1\`, { headers: { "apikey": Deno.env.get("EXTERNAL_SUPABASE_KEY")! } }); checks.external_supabase = extRes.ok; } catch {} // Check own database try { const ownRes = await fetch(\`\${Deno.env.get("SUPABASE_URL")}/rest/v1/user_roles?limit=1\`, { headers: { "apikey": Deno.env.get("SUPABASE_ANON_KEY")! } }); checks.own_database = ownRes.ok; } catch {} const allHealthy = Object.values(checks).every(v => v); return new Response( JSON.stringify({ success: true, healthy: allHealthy, checks, timestamp: new Date().toISOString() }), { status: allHealthy ? 200 : 503, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { return new Response( JSON.stringify({ success: false, healthy: false, error: error.message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });` }; // Gerar arquivos for (const [name, content] of Object.entries(ENDPOINT_TEMPLATES)) { const path = \`../\${name}/index.ts\`; await Deno.writeTextFile(path, content); console.log(\`✅ Created \${name}\`); } console.log(\`\\n🎉 Generated \${Object.keys(ENDPOINT_TEMPLATES).length} endpoints!\`);