riseup-squad18/supabase/functions/_tools/generate-endpoints.ts

499 lines
16 KiB
TypeScript

// 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<any> {
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<any> {
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!\`);