diff --git a/supabase/functions/carbone-io-wrapper/index.ts b/supabase/functions/carbone-io-wrapper/index.ts index 62cf1bd..f4d625e 100644 --- a/supabase/functions/carbone-io-wrapper/index.ts +++ b/supabase/functions/carbone-io-wrapper/index.ts @@ -18,6 +18,7 @@ const ActionSchema = z.object({ const DownloadReportSchema = z.object({ action: z.literal("downloadReport"), plan_estudio_id: z.string().min(1), + body: z.record(z.unknown()), }); type DownloadReportInput = z.infer; @@ -29,10 +30,10 @@ function getAuthHeader(req: Request): string | null { async function loadPlanDatos( supabase: ReturnType>, planEstudioId: string, -): Promise { +): Promise<{ datos: Json; estructura_id: string }> { const { data, error } = await supabase .from("planes_estudio") - .select("datos") + .select("datos, estructura_id") .eq("id", planEstudioId) .maybeSingle(); @@ -52,7 +53,48 @@ async function loadPlanDatos( { plan_estudio_id: planEstudioId }, ); } - return data.datos; + + return { + datos: data.datos, + estructura_id: data.estructura_id, + }; +} + +async function loadTemplateIdForEstructura( + supabase: ReturnType>, + estructuraId: string, +): Promise { + const { data, error } = await supabase + .from("estructuras_plan") + .select("template_id") + .eq("id", estructuraId) + .maybeSingle(); + + if (error) { + throw new HttpError( + 500, + "Error consultando la estructura del plan.", + "DB_ERROR", + { message: error.message, details: error.details, hint: error.hint }, + ); + } + if (!data) { + throw new HttpError( + 404, + "Estructura del plan no encontrada.", + "NOT_FOUND", + { estructura_id: estructuraId }, + ); + } + if (!data.template_id) { + throw new HttpError( + 409, + "La estructura del plan no tiene template_id configurado.", + "MISSING_TEMPLATE_ID", + { estructura_id: estructuraId }, + ); + } + return data.template_id; } Deno.serve(async (req: Request): Promise => { @@ -110,10 +152,9 @@ Deno.serve(async (req: Request): Promise => { } const CARBONE_API_TOKEN = Deno.env.get("CARBONE_API_TOKEN"); - const CARBONE_TEMPLATE_ID = Deno.env.get("CARBONE_TEMPLATE_ID"); const CARBONE_BASE_URL = Deno.env.get("CARBONE_BASE_URL") || "https://carbone.lci.ulsa.mx"; - if (!CARBONE_API_TOKEN || !CARBONE_TEMPLATE_ID) { + if (!CARBONE_API_TOKEN) { throw new HttpError( 500, "Configuración del servidor incompleta.", @@ -121,7 +162,6 @@ Deno.serve(async (req: Request): Promise => { { missing: [ !CARBONE_API_TOKEN ? "CARBONE_API_TOKEN" : null, - !CARBONE_TEMPLATE_ID ? "CARBONE_TEMPLATE_ID" : null, ].filter(Boolean), }, ); @@ -140,12 +180,22 @@ Deno.serve(async (req: Request): Promise => { bodyUnknown, ); - const datos = await loadPlanDatos(supabase, input.plan_estudio_id); + const { datos, estructura_id } = await loadPlanDatos( + supabase, + input.plan_estudio_id, + ); + const templateId = await loadTemplateIdForEstructura( + supabase, + estructura_id, + ); const carbone = new CarboneClient(CARBONE_BASE_URL, CARBONE_API_TOKEN); + const { data: _ignoredData, ...extraBody } = input.body; + + console.log("body:", extraBody); const result = await carbone.render( - CARBONE_TEMPLATE_ID, - { data: datos, convertTo: "pdf" }, + templateId, + { data: datos, ...extraBody }, { download: true }, ); @@ -196,18 +246,36 @@ Deno.serve(async (req: Request): Promise => { { action }, ); } - } catch (err) { - const error = err instanceof HttpError ? err : new HttpError( - 500, - "Error interno del servidor.", - "INTERNAL_SERVER_ERROR", - { - original: err instanceof Error - ? { message: err.message, stack: err.stack } - : err, - }, + } catch (error) { + if (error instanceof HttpError) { + console.error( + `[${new Date().toISOString()}][${functionName}] ⚠️ Handled Error:`, + { + message: error.message, + code: error.code, + internalDetails: error.internalDetails || "N/A", + }, + ); + + return sendError(error.status, error.message, error.code); + } + + const unexpectedError = error instanceof Error + ? error + : new Error(String(error)); + + console.error( + `[${ + new Date().toISOString() + }][${functionName}] 💥 CRITICAL UNHANDLED ERROR:`, + unexpectedError.stack || unexpectedError.message, + ); + + return sendError( + 500, + "Ocurrió un error inesperado en el servidor.", + "INTERNAL_SERVER_ERROR", ); - return sendError(error.status, error.message, error.code); } });