@devlas/dte-sii 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,7 +20,7 @@ const fs = require('fs');
20
20
  const path = require('path');
21
21
  const { XMLParser, XMLBuilder } = require('fast-xml-parser');
22
22
  const bwipjs = require('bwip-js');
23
- const puppeteer = require('puppeteer');
23
+ const { launchBrowser } = require('../utils/browser');
24
24
 
25
25
  // Usar constantes del core
26
26
  const {
@@ -485,7 +485,7 @@ class MuestrasImpresas {
485
485
  }
486
486
 
487
487
  /**
488
- * Genera PDF desde HTML
488
+ * Genera PDF desde HTML y lo escribe a disco.
489
489
  * @private
490
490
  */
491
491
  async _generarPdf({ html, outputPath, browser }) {
@@ -501,6 +501,34 @@ class MuestrasImpresas {
501
501
  await page.close();
502
502
  }
503
503
 
504
+ /**
505
+ * Genera un PDF desde HTML y devuelve el contenido como Buffer (sin escribir a disco).
506
+ * Útil para servir el PDF directamente desde una respuesta HTTP.
507
+ *
508
+ * @param {string} html - HTML a convertir a PDF
509
+ * @param {object} [opts]
510
+ * @param {string} [opts.width='215mm']
511
+ * @param {string} [opts.height='280mm']
512
+ * @returns {Promise<Buffer>}
513
+ */
514
+ async generarPdfBuffer(html, opts = {}) {
515
+ const browser = await launchBrowser();
516
+ try {
517
+ const page = await browser.newPage();
518
+ await page.setContent(html, { waitUntil: 'networkidle0' });
519
+ const pdfBuffer = await page.pdf({
520
+ printBackground: true,
521
+ width: opts.width ?? '215mm',
522
+ height: opts.height ?? '280mm',
523
+ margin: { top: '10mm', right: '10mm', bottom: '10mm', left: '10mm' },
524
+ });
525
+ await page.close();
526
+ return Buffer.from(pdfBuffer);
527
+ } finally {
528
+ await browser.close();
529
+ }
530
+ }
531
+
504
532
  /**
505
533
  * Genera muestras impresas desde archivos XML
506
534
  * @param {Object} options
@@ -524,7 +552,7 @@ class MuestrasImpresas {
524
552
  console.log(` SET-PRUEBAS: ${pruebasDir}`);
525
553
  console.log(` SET-SIMULACION: ${simulacionDir}`);
526
554
 
527
- const browser = await puppeteer.launch({ headless: true });
555
+ const browser = await launchBrowser();
528
556
  const resultado = {
529
557
  success: true,
530
558
  totalDocs: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devlas/dte-sii",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "Facturación y boletas electrónicas para el SII de Chile. Genera, timbra, firma y envía DTEs, libros electrónicos y automatiza la certificación.",
5
5
  "main": "index.js",
6
6
  "types": "dte-sii.d.ts",
@@ -40,6 +40,9 @@
40
40
  "xml-c14n": "^0.0.6",
41
41
  "xml-crypto": "^6.1.2"
42
42
  },
43
+ "optionalDependencies": {
44
+ "@sparticuz/chromium": "^133.0.0"
45
+ },
43
46
  "files": [
44
47
  "index.js",
45
48
  "dte-sii.d.ts",
@@ -0,0 +1,73 @@
1
+ // Copyright (c) 2026 Devlas SpA — https://devlas.cl
2
+ // Licencia MIT. Ver archivo LICENSE para mas detalles.
3
+ /**
4
+ * utils/browser.js
5
+ *
6
+ * Helper para lanzar Puppeteer con el Chromium correcto según el entorno:
7
+ * - Producción / serverless (Railway, Lambda, etc.): usa @sparticuz/chromium
8
+ * - Desarrollo local: usa el Chrome del sistema si @sparticuz/chromium no está disponible
9
+ *
10
+ * Uso:
11
+ * const { launchBrowser } = require('./utils/browser')
12
+ * const browser = await launchBrowser()
13
+ */
14
+
15
+ 'use strict';
16
+
17
+ const puppeteer = require('puppeteer');
18
+
19
+ /**
20
+ * Devuelve las opciones de lanzamiento para puppeteer.launch() según el entorno.
21
+ * @returns {Promise<import('puppeteer').LaunchOptions>}
22
+ */
23
+ async function getLaunchOptions() {
24
+ // 1. Intentar @sparticuz/chromium (viene en el paquete, funciona en serverless)
25
+ try {
26
+ const chromium = require('@sparticuz/chromium');
27
+ return {
28
+ args: chromium.args,
29
+ defaultViewport: chromium.defaultViewport,
30
+ executablePath: await chromium.executablePath(),
31
+ headless: chromium.headless ?? true,
32
+ };
33
+ } catch {
34
+ // No está disponible, continuar con fallback
35
+ }
36
+
37
+ // 2. Ruta explícita por variable de entorno
38
+ if (process.env.PUPPETEER_EXECUTABLE_PATH) {
39
+ return {
40
+ headless: true,
41
+ args: ['--no-sandbox', '--disable-setuid-sandbox'],
42
+ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
43
+ };
44
+ }
45
+
46
+ // 3. Chrome del sistema (rutas comunes Linux / Windows)
47
+ const fs = require('fs');
48
+ const SYSTEM_PATHS = [
49
+ '/usr/bin/google-chrome-stable',
50
+ '/usr/bin/google-chrome',
51
+ '/usr/bin/chromium-browser',
52
+ '/usr/bin/chromium',
53
+ 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
54
+ 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
55
+ ];
56
+ const executablePath = SYSTEM_PATHS.find(p => { try { return fs.existsSync(p) } catch { return false } });
57
+ return {
58
+ headless: true,
59
+ args: ['--no-sandbox', '--disable-setuid-sandbox'],
60
+ ...(executablePath ? { executablePath } : {}),
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Lanza un browser Puppeteer con el Chromium correcto para el entorno actual.
66
+ * @returns {Promise<import('puppeteer').Browser>}
67
+ */
68
+ async function launchBrowser() {
69
+ const opts = await getLaunchOptions();
70
+ return puppeteer.launch(opts);
71
+ }
72
+
73
+ module.exports = { launchBrowser, getLaunchOptions };