/** * Copyright (c) 2026 Niolla * All rights reserved. * * This source code is proprietary and confidential. * Unauthorized copying, modification, distribution, or use * of this file, via any medium, is strictly prohibited. */ // app/logic/documents/engine/pdf.engine.js const puppeteer = require("puppeteer"); const generatePDF = async (html) => { const launchConfig = { args: ["--no-sandbox", "--disable-setuid-sandbox"], }; if (process.env.PUPPETEER_EXECUTABLE_PATH) { launchConfig.executablePath = process.env.PUPPETEER_EXECUTABLE_PATH; } else { launchConfig.headless = true; } const browser = await puppeteer.launch(launchConfig); try { const page = await browser.newPage(); await page.setContent(html, { waitUntil: "load", }); // Wait for fonts await page.evaluate(() => document.fonts?.ready); // Wait for images to fully decode await page.evaluate(async () => { const images = Array.from(document.images); await Promise.all( images.map((img) => { if (img.complete && img.naturalHeight !== 0) return; return new Promise((resolve) => { img.onload = resolve; img.onerror = resolve; }); }), ); }); // Force layout + paint await page.evaluate(() => document.body.getBoundingClientRect()); // Extra stability delay (important on servers) await new Promise((r) => setTimeout(r, 1000)); const buffer = await page.pdf({ format: "A4", printBackground: true, }); return buffer; } finally { await browser.close(); } }; module.exports = { generatePDF };