diff --git a/modules/cda/routes/cda.ts b/modules/cda/routes/cda.ts index 6ce4749136..3f9286c500 100644 --- a/modules/cda/routes/cda.ts +++ b/modules/cda/routes/cda.ts @@ -26,8 +26,11 @@ router.post('/createInformeCDA', Auth.authenticate(), async (req: any, res, next } try { const informe = new InformeCDA(req.body, req.user.usuario); - const fileName = await informe.informe(); - return res.download(fileName); + const pdfBuffer = await informe.informe(); + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); } catch (err) { return next(err); } diff --git a/modules/centroOperativoMedico/controllers/com.controller.ts b/modules/centroOperativoMedico/controllers/com.controller.ts index e7409fe321..ffeaa1ec3d 100644 --- a/modules/centroOperativoMedico/controllers/com.controller.ts +++ b/modules/centroOperativoMedico/controllers/com.controller.ts @@ -5,7 +5,7 @@ const moment = require('moment'); export async function sendMailComprobanteDerivacion(derivacion, to) { const body = { derivacionId: derivacion._id }; const comprobante = new Derivacion({ body }); - const opciones = { header: { height: '3cm' } }; + const opciones = { margin: { top: '3cm' } }; const fileName: any = await comprobante.informe(opciones); const fechaFinalizacion = moment(derivacion.historial.createdAt).format('DD/MM/YYYY'); diff --git a/modules/descargas/ficha-epidemiologica/ficha-body.ts b/modules/descargas/ficha-epidemiologica/ficha-body.ts index ab4798cc6f..cf3fd152c6 100644 --- a/modules/descargas/ficha-epidemiologica/ficha-body.ts +++ b/modules/descargas/ficha-epidemiologica/ficha-body.ts @@ -4,16 +4,18 @@ export class FichaEpidemiologicaBody extends HTMLComponent { template = `

FICHA {{tipo}}

- {{#each arreSecciones}} -
{{seccionNombre}}:
- {{#each arreFields}} - {{#if fieldValor.nombre}} -

{{fieldNombre}}: {{fieldValor.nombre}}

- {{else}} -

{{fieldNombre}}: {{fieldValor}}

- {{/if}} +
+ {{#each arreSecciones}} +
{{seccionNombre}}:
+ {{#each arreFields}} + {{#if fieldValor.nombre}} +

{{fieldNombre}}: {{fieldValor.nombre}}

+ {{else}} +

{{fieldNombre}}: {{fieldValor}}

+ {{/if}} + {{/each}} {{/each}} - {{/each}} +
`; diff --git a/modules/descargas/ficha-epidemiologica/ficha-footer.ts b/modules/descargas/ficha-epidemiologica/ficha-footer.ts index 1ea0e7b6d4..f6fd9ca12d 100644 --- a/modules/descargas/ficha-epidemiologica/ficha-footer.ts +++ b/modules/descargas/ficha-epidemiologica/ficha-footer.ts @@ -4,8 +4,10 @@ import * as moment from 'moment'; export class FichaEpidemiologicaFooter extends HTMLComponent { template = `
-
Fecha y hora de impresión: {{fecha}}
-
Impreso por: {{usuario}}
+ +

Fecha y hora de impresión: {{fecha}}

+

Impreso por: {{usuario}}

+
`; constructor(public usuario) { diff --git a/modules/descargas/informe-censo/censo-body.ts b/modules/descargas/informe-censo/censo-body.ts index 6e19ba16e6..2025e2f1ae 100644 --- a/modules/descargas/informe-censo/censo-body.ts +++ b/modules/descargas/informe-censo/censo-body.ts @@ -6,7 +6,7 @@ export class CensoBody extends HTMLComponent {
- +
@@ -81,45 +81,45 @@ export class CensoBody extends HTMLComponent { diff --git a/modules/descargas/informe-censo/censo-header.ts b/modules/descargas/informe-censo/censo-header.ts index fddb4ecd1b..ec7fe419d4 100644 --- a/modules/descargas/informe-censo/censo-header.ts +++ b/modules/descargas/informe-censo/censo-header.ts @@ -16,11 +16,12 @@ export class CensoHeader extends HTMLComponent { {{/if}} - - + +
+

@@ -34,6 +35,7 @@ export class CensoHeader extends HTMLComponent {

+
`; diff --git a/modules/descargas/informe-censo/censo-mensual-body.ts b/modules/descargas/informe-censo/censo-mensual-body.ts index 51d60dde78..fcf1bd7e77 100644 --- a/modules/descargas/informe-censo/censo-mensual-body.ts +++ b/modules/descargas/informe-censo/censo-mensual-body.ts @@ -10,45 +10,45 @@ export class CensoMensualBody extends HTMLComponent { @@ -90,26 +90,26 @@ export class CensoMensualBody extends HTMLComponent {
Paciente
-
Existencia a las 0 hs
+ Existencia a las 0 hs
-
Ingresos
+ Ingresos
-
Pases de
+ Pases de
-
Egreso
+ Egreso
-
Pases A
+ Pases A
-
Existencia a las 24 hs
+ Existencia a las 24 hs
-
Ingresos y egresos del día
+ Ingresos y egresos del día
-
Pacientes día
+ Pacientes día
-
Días estada
+ Días estada
-
Camas disponibles a las 24hs
+ Camas disponibles a las 24hs
-
Altas
+ Altas
-
Defunciones
+ Defunciones
-
Fecha
+ Fecha
-
Existencia 0 hs
+ Existencia 0 hs
-
Ingresos
+ Ingresos
-
Pases de
+ Pases de
-
Egreso
+ Egreso
-
Pases A
+ Pases A
-
Existencia 24 hs
+ Existencia 24 hs
-
Ingresos- Egresos día
+ Ingresos- Egresos día
-
Pacientes día
+ Pacientes día
-
Camas disponibles 24hs
+ Camas disponibles 24hs
-
Días de estada
+ Días de estada
-
Altas
+ Altas
-
Defunciones
+ Defunciones
- - - - - - - diff --git a/modules/descargas/informe-censo/censo-mensual-header.ts b/modules/descargas/informe-censo/censo-mensual-header.ts index c59289199d..f096d6e7e6 100644 --- a/modules/descargas/informe-censo/censo-mensual-header.ts +++ b/modules/descargas/informe-censo/censo-mensual-header.ts @@ -18,11 +18,12 @@ export class CensoMensualHeader extends HTMLComponent { {{/if}} - - + +
+

@@ -39,6 +40,7 @@ export class CensoMensualHeader extends HTMLComponent {

+
diff --git a/modules/descargas/informe-rup/elementos-rup/adjuntar-documento.component.ts b/modules/descargas/informe-rup/elementos-rup/adjuntar-documento.component.ts index f389acd0c4..8637c17e08 100644 --- a/modules/descargas/informe-rup/elementos-rup/adjuntar-documento.component.ts +++ b/modules/descargas/informe-rup/elementos-rup/adjuntar-documento.component.ts @@ -2,6 +2,7 @@ import { HTMLComponent } from '../../model/html-component.class'; import * as mime from 'mime-types'; import { streamToBase64, readFile } from '../../../../core/tm/controller/file-storage'; import { getArchivoAdjunto } from '../../../../modules/rup/controllers/rup'; +import { streamToJpegDataUri } from '../../../../utils/pdf/puppeteer'; export class AdjuntarDocumentoComponent extends HTMLComponent { @@ -17,7 +18,7 @@ export class AdjuntarDocumentoComponent extends HTMLComponent { {{#each documentos}}

{{ term }}:

- +
{{/each}} @@ -45,8 +46,21 @@ export class AdjuntarDocumentoComponent extends HTMLComponent { return new Promise(async (resolve, reject) => { if (documento.id) { const stream = await getArchivoAdjunto(documento.id); - const base64 = await streamToBase64(stream); - return resolve({ img: base64, term: documento?.descripcion?.term }); + const img = await streamToJpegDataUri(stream, { maxWidth: 1600, quality: 75 }); + return resolve({ img, term: documento?.descripcion?.term }); + + + // const stream = await getArchivoAdjunto(documento.id); + // const dataUri = await streamToOptimizedDataUri(stream, { + // format: 'jpeg', // o 'webp' si necesitás alpha + // quality: 75, + // maxWidth: 1600, + // }); + // return resolve({ img: dataUri, term: documento?.descripcion?.term }); + + + // const base64 = await streamToBase64(stream); + // return resolve({ img: base64, term: documento?.descripcion?.term }); } return; }); diff --git a/modules/descargas/informe-rup/informe-body.ts b/modules/descargas/informe-rup/informe-body.ts index 59d10b9090..21077c827a 100644 --- a/modules/descargas/informe-rup/informe-body.ts +++ b/modules/descargas/informe-rup/informe-body.ts @@ -6,17 +6,17 @@ import { InformeRupFirma } from './informe-firma'; export class InformeRupBody extends HTMLComponent { template = `
+
-
-
+ +
{{ titulo }}
-
-
- Fecha Consulta +
+ Fecha Consulta
{{ fechaEjecucion }}hs @@ -24,28 +24,29 @@ export class InformeRupBody extends HTMLComponent {
{{#if esValidada}} -
- Fecha Validación +
+ Fecha Validación
{{ fechaValidacion }}hs
{{else}} -
- Sin validar +
+ Sin validar
{{/if}}
-
- Inicio de Prestación +
+ Inicio de Prestación
{{ fechaPrestacion }}hs
-
+
+
{{#each registros}} {{{this}}} diff --git a/modules/descargas/informe-rup/informe-firma.ts b/modules/descargas/informe-rup/informe-firma.ts index 146b2ab320..9225def1b4 100644 --- a/modules/descargas/informe-rup/informe-firma.ts +++ b/modules/descargas/informe-rup/informe-firma.ts @@ -6,7 +6,7 @@ import { Profesional } from '../../../core/tm/schemas/profesional'; export class InformeRupFirma extends HTMLComponent { template = ` -
+
@@ -24,7 +24,7 @@ export class InformeRupFirma extends HTMLComponent { {{/if}}
-
+
`; constructor(public profesional, public organizacion) { diff --git a/modules/descargas/informe-rup/informe-footer.ts b/modules/descargas/informe-rup/informe-footer.ts index 78a33d8db1..33965ea4e3 100644 --- a/modules/descargas/informe-rup/informe-footer.ts +++ b/modules/descargas/informe-rup/informe-footer.ts @@ -40,11 +40,11 @@ export class InformeRupFooter extends HTMLComponent { {{/if}} +
{{{ numeracionHTML }}} - `; constructor(public prestacion, public paciente, public organizacion, public user) { @@ -62,7 +62,7 @@ export class InformeRupFooter extends HTMLComponent { pdp: loadImage('templates/rup/informes/img/logo-pdp.png'), }, validacion: this.getDatosValidacion(), - numeracionHTML: ' {{page}} de {{pages}} ', + numeracionHTML: ' de ', notaPie: organizacion.configuraciones?.notaAlPie || InformeRupFooter.notaAlPieDefault }; } diff --git a/modules/descargas/informe-rup/informe-header.ts b/modules/descargas/informe-rup/informe-header.ts index 67a22d036d..9ba2d15b11 100644 --- a/modules/descargas/informe-rup/informe-header.ts +++ b/modules/descargas/informe-rup/informe-header.ts @@ -12,6 +12,7 @@ export class InformeRupHeader extends HTMLComponent { {{else}} +
{{{ organizacion.nombre }}}
{{/if}} @@ -21,6 +22,7 @@ export class InformeRupHeader extends HTMLComponent { +
@@ -43,14 +45,14 @@ export class InformeRupHeader extends HTMLComponent {
-
-
+
+
Obra Social: {{#if paciente.obraSocial}} - {{paciente.obraSocial}} + {{paciente.obraSocial}} {{else}} - sin obra social + sin obra social {{/if}}
@@ -61,7 +63,7 @@ export class InformeRupHeader extends HTMLComponent { Sin datos {{/if}}
-
+
@@ -72,7 +74,7 @@ export class InformeRupHeader extends HTMLComponent { {{ paciente.fechaNacimiento }}
-
+
Nro. de carpeta
@@ -84,7 +86,6 @@ export class InformeRupHeader extends HTMLComponent { {{/if}}
-
{{#if ubicacion}}
@@ -100,52 +101,54 @@ export class InformeRupHeader extends HTMLComponent { - {{#if origenTop}} -
-
DATOS DE ORIGEN DE SOLICITUD
+ {{#if origenTop}} +
+
DATOS DE ORIGEN DE SOLICITUD
+

+ {{{ origen.efectorOrigen }}} +

+
+ +
+
+
Profesional
+
+ {{ origen.profesionalOrigenApellido }}, {{ origen.profesionalOrigenNombre }} +
+
+
+
+
+ Fecha Solicitud +
+
+ {{ origen.fechaSolicitud }}hs +
+
+ {{else}} +
+
Datos de la prestación

- {{{ origen.efectorOrigen }}} + {{{ organizacion.nombre }}}

-
+
+ {{ organizacion.direccion }} +
+
-
-
+
+
Profesional
- {{ origen.profesionalOrigenApellido }}, {{ origen.profesionalOrigenNombre }} + {{ profesional.apellido }}, {{ profesional.nombre }}
+
-
-
-
- Fecha Solicitud -
-
- {{ origen.fechaSolicitud }}hs -
-
- {{else}} -
-
Datos de la prestación
-

- {{{ organizacion.nombre }}} -

-
- {{ organizacion.direccion }} -
-
- -
-
-
Profesional
-
- {{ profesional.apellido }}, {{ profesional.nombre }} -
-
-
- {{/if}} + {{/if}} +
+ {{#unless consultaValidada }}

Prestación no validada por profesional diff --git a/modules/descargas/informe-rup/informe-rup.ts b/modules/descargas/informe-rup/informe-rup.ts index 093bf7f488..c1b50397da 100644 --- a/modules/descargas/informe-rup/informe-rup.ts +++ b/modules/descargas/informe-rup/informe-rup.ts @@ -8,6 +8,7 @@ import { InformeRupFooter } from './informe-footer'; import { elementosRUPAsSet, fulfillPrestacion } from '../../rup/controllers/elementos-rup.controller'; import { findByPaciente } from '../../rup/internacion/camas.controller'; import { findById } from '../../../core-v2/mpi/paciente/paciente.controller'; +import { InformeRupFirma } from './informe-firma'; export class InformeRUP extends InformePDF { @@ -31,6 +32,7 @@ export class InformeRUP extends InformePDF { this.header = new InformeRupHeader(prestacion, paciente, organizacion, cama); this.body = new InformeRupBody(prestacion, paciente, organizacion, this.registroId); + this.firma = new InformeRupFirma(prestacion.solicitud.profesional, organizacion); this.footer = new InformeRupFooter(prestacion, paciente, organizacion, this.usuario); // Obligatorio por ahora para llamar al proccess de la clase abstracta diff --git a/modules/descargas/model/informe.class.ts b/modules/descargas/model/informe.class.ts index 931987aeb3..432f0a6709 100644 --- a/modules/descargas/model/informe.class.ts +++ b/modules/descargas/model/informe.class.ts @@ -1,65 +1,80 @@ import * as fs from 'fs'; import * as path from 'path'; import * as scss from 'node-sass'; -import * as pdf from 'html-pdf'; import { HTMLComponent } from './html-component.class'; -import { enviarMail } from '../../../config.private'; +import { htmlToPdfBuffer } from '../../../utils/pdf/puppeteer'; + +export type InformePdfOptions = { + format?: 'A4' | 'Letter'; + margin?: { + top?: string; // tamaño del header + right?: string; + bottom?: string; // tamaño del footer + left?: string; + }; + landscape?: boolean; +}; export class InformePDF extends HTMLComponent { - template = ` - - - - - - - {{#if css }} - - {{/if}} - - - - {{#if header }} - - {{/if}} - - {{{ body }}} - - {{#if footer }} -
{{{ footer }}}
- {{/if}} - - - `; header: HTMLComponent; body: HTMLComponent; footer: HTMLComponent; - + firma?: HTMLComponent; // firma de profesional style: string; stylesUrl: string[]; - async informe(options: pdf.CreateOptions = null) { - const opciones = { - ...this.getDefaultOptions(), - ...(options || {}) - }; - const html = await this.render(); - return new Promise((resolve, reject) => { - if (!enviarMail.active) { - // Para que ande en Juenkins por ahora - return resolve(''); - } - pdf.create(html, opciones).toFile((err, file) => { - if (err) { - return reject(err); - } - return resolve(file.filename); - }); - }); + wrapTemplate(innerHtml: string, css: string) { + /* Puppeteer requiere que header/footer sean “un solo nodo" + por eso se envuelve el html en un div y se incluye el css para que se aplique a header/footer + */ + return ` +
+ ${css ? `` : ''} + ${innerHtml || ''} +
+ `.trim(); } + buildBodyHtml(css: string, body: string) { + return ` + + + + + + ${css ? `` : ''} + + + ${body || ''} + + + `.trim(); + } + + async informe(options: InformePdfOptions = null): Promise { + // asegura que this.data tenga header/footer/body/css + await this.process(); + + const opciones = { ...this.getDefaultOptions(), ...(options || {}) }; + const css = this.data?.css || ''; + + const headerTemplate = this.wrapTemplate(this.data?.header, css); + const footerTemplate = this.wrapTemplate(this.data?.footer, css); + const bodyHtml = this.buildBodyHtml(css, this.data?.body); + + return htmlToPdfBuffer(bodyHtml, { + format: (opciones?.format as any) || 'A4', + margin: opciones.margin, + landscape: opciones?.landscape || false, + headerTemplate, + footerTemplate, + printBackground: true, + preferCSSPageSize: true, + timeoutMs: 180000 + }); + } public async process() { const data: any = {}; @@ -69,6 +84,9 @@ export class InformePDF extends HTMLComponent { if (this.footer) { data.footer = await this.footer.render(); } + if (this.firma) { + data.firma = await this.firma.render(); + } data.body = await this.body.render(); if (this.style) { @@ -89,27 +107,21 @@ export class InformePDF extends HTMLComponent { return styles.join('\n'); } + private getDefaultOptions() { - const defaultOptions: pdf.CreateOptions = { + const defaultOptions: InformePdfOptions = { format: 'A4', - border: { - // default is 0, units: mm, cm, in, px - top: '.25cm', + margin: { + // por defecto 0, unidades: mm, cm, in, px + top: '7cm', right: '0cm', - bottom: '3cm', + bottom: '3.5cm', left: '0cm' - }, - header: { - height: '7cm', - }, - footer: { - height: '1cm' } }; + return defaultOptions; } - - } diff --git a/modules/descargas/routes/descargas.ts b/modules/descargas/routes/descargas.ts index a5fc8782fd..dfd689e90d 100644 --- a/modules/descargas/routes/descargas.ts +++ b/modules/descargas/routes/descargas.ts @@ -28,7 +28,7 @@ const router = express.Router(); router.post('/reporteDerivacion', Auth.authenticate(), async (req: any, res, next) => { try { const derivacion = new Derivacion(req); - const opciones = { header: { height: '3cm' } }; + const opciones = { margin: { top: '3cm' } }; const fileName: any = await derivacion.informe(opciones); res.download(fileName); } catch (err) { @@ -42,23 +42,28 @@ router.post('/reporteDerivacion', Auth.authenticate(), async (req: any, res, nex */ router.post('/censo', async (req: any, res, next) => { const docCenso = new InformeCenso('diario', req); - const fileName: any = await docCenso.informe(); + const opciones = { margin: { top: '6cm' } }; + const pdfBuffer = await docCenso.informe(opciones); - return res.download(fileName); + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); }); router.post('/censoMensual', async (req: any, res, next) => { const docCenso = new InformeCenso('mensual', req); - const opciones = { header: { height: '4.5cm' }, orientation: 'landscape' }; - const fileName: any = await docCenso.informe(opciones); + const opciones = { margin: { top: '6cm' }, landscape: true }; + const pdfBuffer = await docCenso.informe(opciones); - return res.download(fileName); + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); }); router.post('/anexo-dos', async (req: any, res) => { const docRecupero = new RecuperoCosto(req); - const opciones = { header: { height: '3cm' } }; + const opciones = { margin: { top: '3cm' } }; const fileName: any = await docRecupero.informe(opciones); res.download(fileName); @@ -165,10 +170,12 @@ router.post('/send/:tipo', Auth.authenticate(), async (req, res, next) => { router.post('/constanciaPuco/:tipo?', Auth.authenticate(), async (req: any, res) => { const docPuco = new ConstanciaPuco(req); - const opciones = { header: { height: '3cm' } }; - const fileName: any = await docPuco.informe(opciones); + const opciones = { margin: { top: '3cm' } }; + const pdfBuffer = await docPuco.informe(opciones); - res.download(fileName); + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); }); router.post('/laboratorio/:tipo?', Auth.authenticate(), async (req: any, res, next) => { @@ -183,9 +190,12 @@ router.post('/laboratorio/:tipo?', Auth.authenticate(), async (req: any, res, ne throw new Error('Error al generar laboratorio.'); } const docLaboratorio = new Laboratorio(req.body.protocolo, response, paciente, req.body.usuario); - const opciones = { header: { height: '2cm' } }; - const fileName: any = await docLaboratorio.informe(opciones); - res.download(fileName); + const opciones = { margin: { top: '2cm' } }; + const pdfBuffer = await docLaboratorio.informe(opciones); + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); } catch (err) { await laboratorioLog.error('laboratorio-descargas', req.body.protocolo.data, err, req); @@ -206,9 +216,12 @@ router.post('/fichaEpidemiologia/:tipo?', Auth.authenticate(), async (req: any, throw new Error(`Error al generar ficha de ${req.body.ficha.type.name}`); } const docFichaEpidemiologica = new FichaEpidemiologica(req.body.ficha, req.body.usuario, ficha); - const opciones = { header: { height: '2cm' } }; - const fileName: any = await docFichaEpidemiologica.informe(opciones); - res.download(fileName); + const opciones = { margin: { top: '2.5cm', bottom: '3.5cm' } }; + const pdfBuffer = await docFichaEpidemiologica.informe(opciones); + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); } catch (err) { return next(err); } @@ -219,31 +232,42 @@ router.post('/fichaEpidemiologia/:tipo?', Auth.authenticate(), async (req: any, router.post('/arancelamiento/:tipo?', Auth.authenticate(), async (req: any, res) => { const provincia = configPrivate.provincia || 'neuquen'; - const opciones = { header: { height: '3cm' } }; - let fileName: any; + const opciones = { margin: { top: '3cm' } }; + let pdfBuffer: Buffer; if (provincia === 'neuquen') { const docPuco = new Arancelamiento(req); - fileName = await docPuco.informe(opciones); + pdfBuffer = await docPuco.informe(opciones); + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); } else { const docRecupero = new RecuperoCosto(req); - fileName = await docRecupero.informe(opciones); + pdfBuffer = await docRecupero.informe(opciones); + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); } - res.download(fileName); + return res.send(pdfBuffer); }); router.post('/agenda/:id', Auth.authenticate(), async (req: any, res) => { - const opciones = { header: { height: '3cm' }, orientation: 'landscape' }; + const opciones = { margin: { top: '3cm' }, orientation: 'landscape' }; const docAgenda = new Agenda(req); - const fileName = await docAgenda.informe(opciones); - res.download(fileName); + const pdfBuffer = await docAgenda.informe(opciones); + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); }); // Certificado de etica para profesional desde matriculaciones router.post('/certificadoEtica', Auth.authenticate(), async (req: any, res) => { const certificado = new CertificadoEtica(req); - const opciones = { header: { height: '3cm' } }; - const fileName = await certificado.informe(opciones); - return res.download(fileName); + const opciones = { margin: { top: '3cm' } }; + const pdfBuffer = await certificado.informe(opciones); + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); }); // @@ -252,17 +276,22 @@ router.get('/credencialProfesional/:idProfesional/:idFormacionGrado/:qrcode', Au const idFormacionGrado = req.params.idFormacionGrado; const qrcode = req.params.qrcode; const certificado = new CredencialProfesional(idProfesional, idFormacionGrado, qrcode); - const opciones = { header: { height: '3cm' } }; - const fileName = await certificado.informe(opciones); - return res.download(fileName); + const opciones = { margin: { top: '3cm' } }; + const pdfBuffer = await certificado.informe(opciones); + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); }); router.post('/listadoTurnos', Auth.authenticate(), async (req: any, res, next) => { - const opciones = { header: { height: '3cm' } }; + const opciones = { margin: { top: '3cm' } }; const docTurnos = new InformeTurnos(req); - const fileName: any = await docTurnos.informe(opciones); - return res.download(fileName); + const pdfBuffer = await docTurnos.informe(opciones); + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); }); /** @@ -275,9 +304,11 @@ router.post('/:tipo?', Auth.authenticate(), async (req: any, res, next) => { const idRegistro = req.body.idRegistro; const informe = new InformeRUP(idPrestacion, idRegistro, req.user); - const fileName = await informe.informe(); + const pdfBuffer = await informe.informe(); - return res.download(fileName); + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename="informe.pdf"'); + return res.send(pdfBuffer); } catch (err) { return next(err); } diff --git a/modules/huds/export-huds/exportHuds.controller.ts b/modules/huds/export-huds/exportHuds.controller.ts index 490021ea33..5ea0c2eb09 100644 --- a/modules/huds/export-huds/exportHuds.controller.ts +++ b/modules/huds/export-huds/exportHuds.controller.ts @@ -8,14 +8,24 @@ import { exportHudsLog } from './exportHuds.log'; import { ExportHudsModel } from './exportHuds.schema'; import { getHUDSExportarModel } from './hudsFiles'; import { Paciente } from '../../../core-v2/mpi'; +const pLimit = require('p-limit'); import moment = require('moment'); +const safe = (s: string) => + (s || '') + .replace(/[<>:"/\\|?*\x00-\x1F]/g, '-') // al parecer inválidos windows/zip + .replace(/\s+/g, ' ') + .trim() + .slice(0, 150); + export async function createFile(idExportHuds) { return new Promise(async (resolve, reject) => { const peticionExport: any = await ExportHudsModel.findById(idExportHuds); + let fechaCondicion = null; let prestaciones: any[] = []; let cdas = []; + if (peticionExport.prestaciones.length) { prestaciones = await Prestacion.find({ _id: { $in: peticionExport.prestaciones } }); } else { @@ -52,102 +62,107 @@ export async function createFile(idExportHuds) { const cdaFiles = makeFs(); cdas = await cdaFiles.find(queryCda).toArray(); } + const fecha = moment(peticionExport.createAt).format('YYYY-MM-DD'); + const archive = archiver('zip', { zlib: { level: 9 } }); - const archive = archiver('zip', { - zlib: { level: 9 } + archive.on('warning', (w) => { + exportHudsLog.error('warning creando archivo .zip', {}, w); }); - const metadata = { - user: peticionExport.user - }; - const options = { - filename: `HUDS-${peticionExport.pacienteNombre ? peticionExport.pacienteNombre : ''}-${fecha}`, - contentType: 'application/zip', - metadata - }; - const HudsFiles = getHUDSExportarModel(); + + const filename = `HUDS-${safe(peticionExport.pacienteNombre || '')}-${fecha}`; const objectLog = { usuario: peticionExport.user.usuario, - huds: options.filename, + huds: filename, organizacion: peticionExport.user.organizacion }; - try { - HudsFiles.writeFile( - options - , - archive, - (_error: any, archivo) => { - if (_error) { - return reject(); - } - peticionExport.idHudsFiles = archivo._id; - peticionExport.status = 'completed'; - peticionExport.updatedAt = new Date(); - peticionExport.save(); - return resolve(null); - } - ); + const HudsFiles = getHUDSExportarModel(); - exportHudsLog.info('exportaHuds', objectLog); - } catch (error) { - throw error; - } - archive.on('error', (err) => { - throw err; + // stream real para esperar finish/close + const ws = HudsFiles.createWriteStream({ + filename, + contentType: 'application/zip', + metadata: { user: peticionExport.user } + }); + + ws.on('error', reject); + archive.pipe(ws); + + const stored = new Promise((res, rej) => { + ws.on('finish', () => res(null)); + ws.on('close', (file) => res(file)); + ws.on('error', rej); }); - const getData = () => { - return Promise.all(prestaciones.map(async (prestacion: any) => { + + const limit = pLimit(2); + + const getData = () => Promise.all(prestaciones.map((prestacion: any) => + limit(async () => { try { const informe = new InformeRUP(prestacion.id, null, peticionExport.user); - const archivo = await informe.informe(); - const nombreArchivo = peticionExport.prestaciones.length ? prestacion.paciente.documento : prestacion.solicitud.tipoPrestacion.term; - const fechaArchivo = moment(prestacion.solicitud.fecha).format('YYYY-MM-DD-hhmmss'); - archive.file(`${archivo}`, { name: `${fechaArchivo} - ${nombreArchivo}.pdf` }); + const pdfBuffer: Buffer = await informe.informe(); + const nombreArchivo = peticionExport.prestaciones.length + ? prestacion.paciente.documento + : prestacion.solicitud.tipoPrestacion.term; + + const fechaArchivo = moment(prestacion.solicitud.fecha).format('YYYY-MM-DD-HHmmss'); + + archive.append(pdfBuffer, { name: `${fechaArchivo} - ${safe(nombreArchivo)}.pdf` }); } catch (error) { - exportHudsLog.error('Crear pdf', objectLog, error); + exportHudsLog.error('Crear pdf', { prestacion: prestacion?.id, ...objectLog }, error); } - })); - }; - const getCdas = (excluye: string[]) => { - return Promise.all(cdas.map(async (cda: any) => { - if (!excluye.includes(cda.metadata.prestacion?.snomed?.conceptId)) { + }) + )); + + const getCdas = (excluye: string[]) => Promise.all(cdas.map((cda: any) => + limit(async () => { + try { + if (excluye.includes(cda.metadata.prestacion?.snomed?.conceptId)) { return; } + + const fechaArchivo = moment(cda.metadata.fecha).format('YYYY-MM-DD-HHmmss'); + const nombreArchivo = cda.metadata.prestacion?.snomed?.term || 'CDA'; + if (cda.metadata.adjuntos?.length > 0) { const realName = cda.metadata.adjuntos[0].id; - try { - const fileCda = await getCdaAdjunto(cda, realName); - archive.append(fileCda.stream, { name: `${moment(cda.metadata.fecha).format('YYYY-MM-DD-hhmmss')} - ${cda.metadata.prestacion.snomed.term}.pdf` }); - - } catch (error) { - exportHudsLog.error('Crear cda', objectLog, error); - } - } else { - if (cda.metadata.prestacion && cda.metadata.prestacion.snomed.conceptId !== '33879002') { - try { - let codificacionCDA; - await cdaToJSON(cda._id).then(async (cdaData: any) => { - codificacionCDA = cdaData.ClinicalDocument.component.structuredBody.component.section; - }); - cda.metadata['codificacion'] = codificacionCDA; - const informe = new InformeCDA(cda.metadata, peticionExport.usuario); - const archivo: any = await informe.informe(); - const fechaArchivo = moment(cda.metadata.fecha).format('YYYY-MM-DD-hhmmss'); - const nombreArchivo = cda.metadata.prestacion.snomed.term; - archive.file(`${archivo}`, { name: `${fechaArchivo} - ${nombreArchivo}.pdf` }); - } catch (error) { - exportHudsLog.error('Crear informe cda', objectLog, error); - } - } + const fileCda = await getCdaAdjunto(cda, realName); + + archive.append(fileCda.stream, { name: `${fechaArchivo} - ${safe(nombreArchivo)}.pdf` }); + return; + } + + if (cda.metadata.prestacion && cda.metadata.prestacion.snomed.conceptId !== '33879002') { + const cdaData: any = await cdaToJSON(cda._id); + const codificacionCDA = cdaData.ClinicalDocument.component.structuredBody.component.section; + cda.metadata['codificacion'] = codificacionCDA; + + const informe = new InformeCDA(cda.metadata, peticionExport.usuario); + + const pdfBuffer: Buffer = await informe.informe(); // mismo cambio que InformeRUP + archive.append(pdfBuffer, { name: `${fechaArchivo} - ${safe(nombreArchivo)}.pdf` }); } + } catch (error) { + exportHudsLog.error('Crear cda', { cda: cda?._id, ...objectLog }, error); } - })); - }; - // Primero obtengo los pdf y luego cierro el archivo - if (prestaciones) { - await getData(); - } - if (cdas) { - await getCdas(peticionExport.excluye); + }) + )); + + try { + if (prestaciones?.length) { await getData(); } + if (cdas?.length) { await getCdas(peticionExport.excluye || []); } + + await archive.finalize(); + const fileDoc = await stored; + + peticionExport.idHudsFiles = fileDoc?._id || ws.id; + peticionExport.status = 'completed'; + peticionExport.updatedAt = new Date(); + await peticionExport.save(); + + resolve(null); + } catch (e) { + reject(e); } - archive.finalize(); }); + + } diff --git a/package-lock.json b/package-lock.json index 73d302813e..90b1456510 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "api", - "version": "5.130.1", + "version": "5.141.0", "license": "ISC", "dependencies": { "@agm/core": "^1.0.0-beta.5", @@ -54,7 +54,6 @@ "geojson": "^0.4.1", "gridfs-stream": "^1.1.1", "handlebars": "^4.1.0", - "html-pdf": "^2.2.0", "http": "0.0.0", "http-status-codes": "^1.1.6", "into-stream": "^5.0.0", @@ -75,10 +74,11 @@ "node-sass": "^7.0.0", "node-schedule": "^1.2.4", "nodemailer": "^6.9.1", + "p-limit": "^3.1.0", "passport": "^0.3.2", "passport-jwt": "^4.0.0", "pdfkit": "^0.9.0", - "phantomjs-prebuilt-that-works": "^3.0.1", + "puppeteer": "^19.11.1", "request": "^2.83.0", "require-dir": "^0.3.0", "sha1": "^1.1.1", @@ -2016,16 +2016,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": { - "version": "2.6.6", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, "node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": { "version": "3.0.2", "license": "ISC", @@ -2052,22 +2042,6 @@ "node": ">=10" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/tr46": { - "version": "0.0.3", - "license": "MIT" - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/webidl-conversions": { - "version": "3.0.1", - "license": "BSD-2-Clause" - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/whatwg-url": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { "version": "4.0.0", "license": "ISC" @@ -3112,6 +3086,21 @@ "node": ">=8" } }, + "node_modules/@semantic-release/release-notes-generator/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@semantic-release/release-notes-generator/node_modules/p-locate": { "version": "4.1.0", "dev": true, @@ -3489,6 +3478,15 @@ "version": "13.1.0", "license": "MIT" }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "4.29.0", "dev": true, @@ -5699,7 +5697,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5868,6 +5865,17 @@ "node": ">=10" } }, + "node_modules/chromium-bidi": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.7.tgz", + "integrity": "sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==", + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/ci-info": { "version": "1.6.0", "dev": true, @@ -6462,6 +6470,21 @@ "dev": true, "license": "MIT" }, + "node_modules/conventional-changelog-writer/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/conventional-changelog-writer/node_modules/p-locate": { "version": "4.1.0", "dev": true, @@ -6809,6 +6832,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/conventional-commits-parser/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/conventional-commits-parser/node_modules/p-locate": { "version": "4.1.0", "dev": true, @@ -7146,6 +7184,14 @@ "node": ">=0.8" } }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "license": "MIT", @@ -7487,6 +7533,11 @@ "node": ">=0.10.0" } }, + "node_modules/devtools-protocol": { + "version": "0.0.1107588", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz", + "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==" + }, "node_modules/dezalgo": { "version": "1.0.3", "license": "ISC", @@ -8140,6 +8191,14 @@ "es6-promise": "^4.0.3" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-html": { "version": "1.0.3", "license": "MIT" @@ -9338,30 +9397,6 @@ "node": ">=0.10.0" } }, - "node_modules/extract-zip": { - "version": "1.6.7", - "license": "BSD-2-Clause", - "dependencies": { - "concat-stream": "1.6.2", - "debug": "2.6.9", - "mkdirp": "0.5.1", - "yauzl": "2.4.1" - }, - "bin": { - "extract-zip": "cli.js" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, "node_modules/extsprintf": { "version": "1.3.0", "engines": [ @@ -9544,13 +9579,6 @@ "bser": "^2.0.0" } }, - "node_modules/fd-slicer": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/figures": { "version": "3.2.0", "dev": true, @@ -9709,6 +9737,20 @@ "node": ">=8" } }, + "node_modules/find-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/find-up/node_modules/p-locate": { "version": "4.1.0", "license": "MIT", @@ -9915,15 +9957,6 @@ "version": "1.0.0", "license": "MIT" }, - "node_modules/fs-extra": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - } - }, "node_modules/fs-minipass": { "version": "2.1.0", "license": "ISC", @@ -10451,17 +10484,6 @@ "curriable": "^1.1.0" } }, - "node_modules/hasha": { - "version": "2.2.0", - "license": "MIT", - "dependencies": { - "is-stream": "^1.0.1", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hook-std": { "version": "2.0.0", "dev": true, @@ -10482,19 +10504,6 @@ "whatwg-encoding": "^1.0.1" } }, - "node_modules/html-pdf": { - "version": "2.2.0", - "license": "MIT", - "bin": { - "html-pdf": "bin/index.js" - }, - "engines": { - "node": ">=4.0.0" - }, - "optionalDependencies": { - "phantomjs-prebuilt": "^2.1.4" - } - }, "node_modules/htmlparser2": { "version": "3.10.1", "license": "MIT", @@ -10687,7 +10696,6 @@ }, "node_modules/import-fresh": { "version": "3.2.1", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -10699,7 +10707,6 @@ }, "node_modules/import-fresh/node_modules/resolve-from": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -11225,6 +11232,7 @@ }, "node_modules/is-stream": { "version": "1.1.0", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12574,13 +12582,6 @@ "dev": true, "license": "MIT" }, - "node_modules/jsonfile": { - "version": "2.4.0", - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/jsonparse": { "version": "1.3.1", "dev": true, @@ -12665,10 +12666,6 @@ "version": "2.3.1", "license": "Apache-2.0" }, - "node_modules/kew": { - "version": "0.7.0", - "license": "Apache-2.0" - }, "node_modules/keyv": { "version": "3.0.0", "license": "MIT", @@ -12684,13 +12681,6 @@ "node": ">=0.10.0" } }, - "node_modules/klaw": { - "version": "1.3.1", - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.9" - } - }, "node_modules/kleur": { "version": "3.0.3", "dev": true, @@ -13554,6 +13544,11 @@ "version": "4.0.0", "license": "ISC" }, + "node_modules/mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" + }, "node_modules/mixin-deep": { "version": "1.3.1", "dev": true, @@ -14312,10 +14307,41 @@ } }, "node_modules/node-fetch": { - "version": "2.6.1", - "license": "MIT", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, "engines": { "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "node_modules/node-forge": { @@ -20162,13 +20188,17 @@ } }, "node_modules/p-limit": { - "version": "2.2.1", - "license": "MIT", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { @@ -20181,6 +20211,20 @@ "node": ">=6" } }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-map": { "version": "2.1.0", "dev": true, @@ -20231,7 +20275,8 @@ }, "node_modules/p-try": { "version": "2.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "engines": { "node": ">=6" } @@ -20296,7 +20341,6 @@ }, "node_modules/parent-module": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -20473,59 +20517,6 @@ "version": "2.1.0", "license": "MIT" }, - "node_modules/phantomjs-prebuilt": { - "version": "2.1.16", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "es6-promise": "^4.0.3", - "extract-zip": "^1.6.5", - "fs-extra": "^1.0.0", - "hasha": "^2.2.0", - "kew": "^0.7.0", - "progress": "^1.1.8", - "request": "^2.81.0", - "request-progress": "^2.0.1", - "which": "^1.2.10" - }, - "bin": { - "phantomjs": "bin/phantomjs" - } - }, - "node_modules/phantomjs-prebuilt-that-works": { - "version": "3.0.1", - "bundleDependencies": [ - "extract-zip", - "fs-extra", - "hasha", - "kew", - "progress", - "request", - "request-progress", - "which" - ], - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "es6-promise": "^3.2.1", - "extract-zip": "~1.5.0", - "fs-extra": "~0.30.0", - "hasha": "^2.2.0", - "kew": "~0.7.0", - "progress": "~1.1.8", - "request": "~2.74.0", - "request-progress": "~2.0.1", - "which": "~1.2.10" - }, - "bin": { - "phantomjs": "bin/phantomjs" - } - }, - "node_modules/phantomjs-prebuilt-that-works/node_modules/es6-promise": { - "version": "3.3.1", - "license": "MIT" - }, "node_modules/picomatch": { "version": "2.3.1", "dev": true, @@ -20544,23 +20535,6 @@ "node": ">=4" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/pino": { "version": "6.13.4", "license": "MIT", @@ -20949,12 +20923,6 @@ "version": "1.0.0", "license": "MIT" }, - "node_modules/progress": { - "version": "1.1.8", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/proj4": { "version": "2.5.0", "license": "MIT", @@ -20993,6 +20961,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pseudomap": { "version": "1.0.2", "license": "ISC" @@ -21021,6 +20994,379 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.11.1.tgz", + "integrity": "sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==", + "deprecated": "< 24.15.0 is no longer supported", + "hasInstallScript": true, + "dependencies": { + "@puppeteer/browsers": "0.5.0", + "cosmiconfig": "8.1.3", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "puppeteer-core": "19.11.1" + } + }, + "node_modules/puppeteer/node_modules/@puppeteer/browsers": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz", + "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==", + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=14.1.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/puppeteer/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/puppeteer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/puppeteer/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/puppeteer/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/puppeteer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/puppeteer/node_modules/cosmiconfig": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + } + }, + "node_modules/puppeteer/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/puppeteer/node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/puppeteer/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/puppeteer/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/puppeteer/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/puppeteer/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/puppeteer/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/puppeteer/node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/puppeteer/node_modules/puppeteer-core": { + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.11.1.tgz", + "integrity": "sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==", + "dependencies": { + "@puppeteer/browsers": "0.5.0", + "chromium-bidi": "0.4.7", + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.1107588", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.13.0" + }, + "engines": { + "node": ">=14.14.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/puppeteer/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/puppeteer/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/puppeteer/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/puppeteer/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer/node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/q": { "version": "1.5.1", "dev": true, @@ -21453,13 +21799,6 @@ "node": ">= 4" } }, - "node_modules/request-progress": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "throttleit": "^1.0.0" - } - }, "node_modules/request-promise-core": { "version": "1.1.3", "dev": true, @@ -22193,6 +22532,21 @@ "node": ">=8" } }, + "node_modules/semantic-release/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/semantic-release/node_modules/p-locate": { "version": "4.1.0", "dev": true, @@ -24431,10 +24785,6 @@ "dev": true, "license": "MIT" }, - "node_modules/throttleit": { - "version": "1.0.0", - "license": "MIT" - }, "node_modules/through": { "version": "2.3.8", "license": "MIT" @@ -25048,6 +25398,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "node_modules/undefsafe": { "version": "2.0.2", "dev": true, @@ -25488,6 +25847,7 @@ }, "node_modules/which": { "version": "1.3.1", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -25940,17 +26300,21 @@ "decamelize": "^1.2.0" } }, - "node_modules/yauzl": { - "version": "2.4.1", - "license": "MIT", - "dependencies": { - "fd-slicer": "~1.0.1" - } - }, "node_modules/yeast": { "version": "0.1.2", "license": "MIT" }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/z-schema": { "version": "4.2.3", "license": "MIT", @@ -27987,12 +28351,6 @@ } } }, - "node-fetch": { - "version": "2.6.6", - "requires": { - "whatwg-url": "^5.0.0" - } - }, "rimraf": { "version": "3.0.2", "requires": { @@ -28005,19 +28363,6 @@ "lru-cache": "^6.0.0" } }, - "tr46": { - "version": "0.0.3" - }, - "webidl-conversions": { - "version": "3.0.1" - }, - "whatwg-url": { - "version": "5.0.0", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "yallist": { "version": "4.0.0" } @@ -28725,6 +29070,15 @@ "version": "3.0.0", "dev": true }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "4.1.0", "dev": true, @@ -29022,6 +29376,15 @@ "@types/yargs-parser": { "version": "13.1.0" }, + "@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, "@typescript-eslint/eslint-plugin": { "version": "4.29.0", "dev": true, @@ -30434,8 +30797,7 @@ "version": "1.0.0" }, "callsites": { - "version": "3.1.0", - "dev": true + "version": "3.1.0" }, "camelcase": { "version": "5.3.1" @@ -30542,6 +30904,14 @@ "chownr": { "version": "2.0.0" }, + "chromium-bidi": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.7.tgz", + "integrity": "sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==", + "requires": { + "mitt": "3.0.0" + } + }, "ci-info": { "version": "1.6.0", "dev": true @@ -30935,6 +31305,15 @@ "version": "1.2.5", "dev": true }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "4.1.0", "dev": true, @@ -31151,6 +31530,15 @@ "yargs-parser": "^18.1.3" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "4.1.0", "dev": true, @@ -31364,6 +31752,14 @@ "moment-timezone": "^0.5.23" } }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + } + }, "cross-spawn": { "version": "7.0.3", "requires": { @@ -31581,6 +31977,11 @@ "version": "2.1.0", "dev": true }, + "devtools-protocol": { + "version": "0.0.1107588", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz", + "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==" + }, "dezalgo": { "version": "1.0.3", "requires": { @@ -32055,6 +32456,11 @@ "es6-promise": "^4.0.3" } }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" + }, "escape-html": { "version": "1.0.3" }, @@ -32851,26 +33257,6 @@ } } }, - "extract-zip": { - "version": "1.6.7", - "requires": { - "concat-stream": "1.6.2", - "debug": "2.6.9", - "mkdirp": "0.5.1", - "yauzl": "2.4.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0" - } - } - }, "extsprintf": { "version": "1.3.0" }, @@ -32995,12 +33381,6 @@ "bser": "^2.0.0" } }, - "fd-slicer": { - "version": "1.0.1", - "requires": { - "pend": "~1.2.0" - } - }, "figures": { "version": "3.2.0", "dev": true, @@ -33105,6 +33485,14 @@ "p-locate": "^4.1.0" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "4.1.0", "requires": { @@ -33248,14 +33636,6 @@ "fs-constants": { "version": "1.0.0" }, - "fs-extra": { - "version": "1.0.0", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - } - }, "fs-minipass": { "version": "2.1.0", "requires": { @@ -33605,13 +33985,6 @@ "curriable": "^1.1.0" } }, - "hasha": { - "version": "2.2.0", - "requires": { - "is-stream": "^1.0.1", - "pinkie-promise": "^2.0.0" - } - }, "hook-std": { "version": "2.0.0", "dev": true @@ -33626,12 +33999,6 @@ "whatwg-encoding": "^1.0.1" } }, - "html-pdf": { - "version": "2.2.0", - "requires": { - "phantomjs-prebuilt": "^2.1.4" - } - }, "htmlparser2": { "version": "3.10.1", "requires": { @@ -33766,15 +34133,13 @@ }, "import-fresh": { "version": "3.2.1", - "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" }, "dependencies": { "resolve-from": { - "version": "4.0.0", - "dev": true + "version": "4.0.0" } } }, @@ -34099,7 +34464,8 @@ "version": "1.1.0" }, "is-stream": { - "version": "1.1.0" + "version": "1.1.0", + "dev": true }, "is-string": { "version": "1.0.6", @@ -35062,12 +35428,6 @@ } } }, - "jsonfile": { - "version": "2.4.0", - "requires": { - "graceful-fs": "^4.1.6" - } - }, "jsonparse": { "version": "1.3.1", "dev": true @@ -35125,9 +35485,6 @@ "kareem": { "version": "2.3.1" }, - "kew": { - "version": "0.7.0" - }, "keyv": { "version": "3.0.0", "requires": { @@ -35138,12 +35495,6 @@ "version": "6.0.2", "dev": true }, - "klaw": { - "version": "1.3.1", - "requires": { - "graceful-fs": "^4.1.9" - } - }, "kleur": { "version": "3.0.3", "dev": true @@ -35720,6 +36071,11 @@ } } }, + "mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" + }, "mixin-deep": { "version": "1.3.1", "dev": true, @@ -36227,7 +36583,33 @@ } }, "node-fetch": { - "version": "2.6.1" + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } }, "node-forge": { "version": "0.7.6" @@ -40568,15 +40950,27 @@ "version": "3.0.0" }, "p-limit": { - "version": "2.2.1", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "3.0.0", "requires": { "p-limit": "^2.0.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + } } }, "p-map": { @@ -40608,7 +41002,9 @@ } }, "p-try": { - "version": "2.2.0" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "package-json": { "version": "4.0.1", @@ -40655,7 +41051,6 @@ }, "parent-module": { "version": "1.0.1", - "dev": true, "requires": { "callsites": "^3.0.0" } @@ -40773,40 +41168,6 @@ "performance-now": { "version": "2.1.0" }, - "phantomjs-prebuilt": { - "version": "2.1.16", - "optional": true, - "requires": { - "es6-promise": "^4.0.3", - "extract-zip": "^1.6.5", - "fs-extra": "^1.0.0", - "hasha": "^2.2.0", - "kew": "^0.7.0", - "progress": "^1.1.8", - "request": "^2.81.0", - "request-progress": "^2.0.1", - "which": "^1.2.10" - } - }, - "phantomjs-prebuilt-that-works": { - "version": "3.0.1", - "requires": { - "es6-promise": "^3.2.1", - "extract-zip": "~1.5.0", - "fs-extra": "~0.30.0", - "hasha": "^2.2.0", - "kew": "~0.7.0", - "progress": "~1.1.8", - "request": "~2.74.0", - "request-progress": "~2.0.1", - "which": "~1.2.10" - }, - "dependencies": { - "es6-promise": { - "version": "3.3.1" - } - } - }, "picomatch": { "version": "2.3.1", "dev": true @@ -40814,15 +41175,6 @@ "pify": { "version": "3.0.0" }, - "pinkie": { - "version": "2.0.4" - }, - "pinkie-promise": { - "version": "2.0.1", - "requires": { - "pinkie": "^2.0.0" - } - }, "pino": { "version": "6.13.4", "requires": { @@ -41092,9 +41444,6 @@ "process-warning": { "version": "1.0.0" }, - "progress": { - "version": "1.1.8" - }, "proj4": { "version": "2.5.0", "requires": { @@ -41122,6 +41471,11 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "pseudomap": { "version": "1.0.2" }, @@ -41142,6 +41496,251 @@ "punycode": { "version": "2.1.1" }, + "puppeteer": { + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.11.1.tgz", + "integrity": "sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==", + "requires": { + "@puppeteer/browsers": "0.5.0", + "cosmiconfig": "8.1.3", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "puppeteer-core": "19.11.1" + }, + "dependencies": { + "@puppeteer/browsers": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz", + "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==", + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "cosmiconfig": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "requires": { + "pend": "~1.2.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "puppeteer-core": { + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.11.1.tgz", + "integrity": "sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==", + "requires": { + "@puppeteer/browsers": "0.5.0", + "chromium-bidi": "0.4.7", + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.1107588", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.13.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "optional": true, + "peer": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "requires": {} + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } + }, "q": { "version": "1.5.1", "dev": true @@ -41432,12 +42031,6 @@ "uuid": "^3.3.2" } }, - "request-progress": { - "version": "2.0.1", - "requires": { - "throttleit": "^1.0.0" - } - }, "request-promise-core": { "version": "1.1.3", "dev": true, @@ -41932,6 +42525,15 @@ "version": "2.1.0", "dev": true }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "4.1.0", "dev": true, @@ -43448,9 +44050,6 @@ "version": "4.1.0", "dev": true }, - "throttleit": { - "version": "1.0.0" - }, "through": { "version": "2.3.8" }, @@ -43876,6 +44475,15 @@ } } }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "undefsafe": { "version": "2.0.2", "dev": true, @@ -44197,6 +44805,7 @@ }, "which": { "version": "1.3.1", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -44494,15 +45103,14 @@ "yargs-parser": { "version": "20.2.9" }, - "yauzl": { - "version": "2.4.1", - "requires": { - "fd-slicer": "~1.0.1" - } - }, "yeast": { "version": "0.1.2" }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, "z-schema": { "version": "4.2.3", "requires": { diff --git a/package.json b/package.json index 821ca3d7d4..0b069e7ad3 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,22 @@ "version": "5.141.0", "description": "API para ANDES", "main": "index.js", + "scripts": { + "startNode": "tsc && gulp && concurrently \"npm run node\" ", + "start": "DEBUG=andes concurrently -r \"npm run tsc:w\" \"npm run node\" ", + "node": "nodemon -q ./index.js", + "tsc": "tsc", + "tsc:w": "tsc -w", + "tsc:next": "tsc --target es2018 --lib es2018", + "jobs": "tsc && node jobs/scheduler.js", + "lint": "eslint -c .eslintrc.js --ext .ts .", + "lint:fix": "eslint -c .eslintrc.js --ext .ts . --fix", + "test": "MONGOMS_DEBUG=1 jest", + "testing": "NODE_ENV=test npm start", + "docker:up": "docker-compose -p andes_dev up -d ", + "docker:down": "docker-compose -p andes_dev down", + "docker:seed": "./seed.sh" + }, "dependencies": { "@agm/core": "^1.0.0-beta.5", "@andes/api-tool": "^2.5.0", @@ -49,7 +65,6 @@ "geojson": "^0.4.1", "gridfs-stream": "^1.1.1", "handlebars": "^4.1.0", - "html-pdf": "^2.2.0", "http": "0.0.0", "http-status-codes": "^1.1.6", "into-stream": "^5.0.0", @@ -70,10 +85,11 @@ "node-sass": "^7.0.0", "node-schedule": "^1.2.4", "nodemailer": "^6.9.1", + "p-limit": "^3.1.0", "passport": "^0.3.2", "passport-jwt": "^4.0.0", "pdfkit": "^0.9.0", - "phantomjs-prebuilt-that-works": "^3.0.1", + "puppeteer": "^19.11.1", "request": "^2.83.0", "require-dir": "^0.3.0", "sha1": "^1.1.1", @@ -92,21 +108,27 @@ "xmldom": "^0.1.27", "xmljson": "^0.2.0" }, - "scripts": { - "startNode": "tsc && gulp && concurrently \"npm run node\" ", - "start": "DEBUG=andes concurrently -r \"npm run tsc:w\" \"npm run node\" ", - "node": "nodemon -q ./index.js", - "tsc": "tsc", - "tsc:w": "tsc -w", - "tsc:next": "tsc --target es2018 --lib es2018", - "jobs": "tsc && node jobs/scheduler.js", - "lint": "eslint -c .eslintrc.js --ext .ts .", - "lint:fix": "eslint -c .eslintrc.js --ext .ts . --fix", - "test": "MONGOMS_DEBUG=1 jest", - "testing": "NODE_ENV=test npm start", - "docker:up": "docker-compose -p andes_dev up -d ", - "docker:down": "docker-compose -p andes_dev down", - "docker:seed": "./seed.sh" + "devDependencies": { + "@semantic-release/changelog": "^5.0.1", + "@semantic-release/git": "^9.0.0", + "@types/jest": "^24.0.22", + "@types/mongoose": "^5.7.36", + "@types/node": "^14.11.9", + "@types/request": "^2.48.5", + "@typescript-eslint/eslint-plugin": "^4.29.0", + "@typescript-eslint/eslint-plugin-tslint": "^4.29.0", + "@typescript-eslint/parser": "^4.33.0", + "before": "0.0.1", + "chai": "^4.1.2", + "eslint": "^7.32.0", + "eslint-plugin-import": "^2.23.4", + "eslint-plugin-prefer-arrow": "^1.2.3", + "jest": "^24.9.0", + "mongodb-memory-server-global": "^8.4.0", + "nodemon": "^1.17.4", + "semantic-release": "^17.0.8", + "ts-jest": "^24.1.0", + "tslint-eslint-rules": "^4.1.1" }, "repository": { "type": "git", @@ -164,27 +186,5 @@ "@semantic-release/git" ] }, - "homepage": "https://github.com/andes/api#readme", - "devDependencies": { - "@semantic-release/changelog": "^5.0.1", - "@semantic-release/git": "^9.0.0", - "@types/jest": "^24.0.22", - "@types/mongoose": "^5.7.36", - "@types/node": "^14.11.9", - "@types/request": "^2.48.5", - "@typescript-eslint/eslint-plugin": "^4.29.0", - "@typescript-eslint/eslint-plugin-tslint": "^4.29.0", - "@typescript-eslint/parser": "^4.33.0", - "before": "0.0.1", - "chai": "^4.1.2", - "eslint": "^7.32.0", - "eslint-plugin-import": "^2.23.4", - "eslint-plugin-prefer-arrow": "^1.2.3", - "jest": "^24.9.0", - "mongodb-memory-server-global": "^8.4.0", - "nodemon": "^1.17.4", - "semantic-release": "^17.0.8", - "ts-jest": "^24.1.0", - "tslint-eslint-rules": "^4.1.1" - } + "homepage": "https://github.com/andes/api#readme" } diff --git a/templates/ficha-epidemiologica/ficha-epidemiologica.scss b/templates/ficha-epidemiologica/ficha-epidemiologica.scss index 387cd8adae..6cac6f722a 100644 --- a/templates/ficha-epidemiologica/ficha-epidemiologica.scss +++ b/templates/ficha-epidemiologica/ficha-epidemiologica.scss @@ -1,18 +1,35 @@ .contenedor-secundario { display: block; - text-align: center; + width: 100%; + margin-left: 1.5cm; font-size: .25cm; + + h6 { + font-size: 0.3cm; + margin-bottom: 0.25cm; + } + + p { + margin: 5px 0; + font-family: Arial, sans-serif; + font-size: .27cm; + } } -p { - margin: 5px 0; - font-family: Arial, sans-serif; - font-size: .27cm; +hr { + margin-left: .75cm; + width: 90%; } .foot { - font-family: Arial, sans-serif; - font-size: 10px; + display: block; + width: 100%; + margin: .5cm 1.5cm; + + p { + font-family: Arial, sans-serif; + font-size: .2cm; + } } .logoHeader { diff --git a/templates/rup/informes/sass/main.scss b/templates/rup/informes/sass/main.scss index 9c1ad2c349..a1327248b7 100644 --- a/templates/rup/informes/sass/main.scss +++ b/templates/rup/informes/sass/main.scss @@ -2,7 +2,7 @@ @import 'variables/cromaticas'; html { - display: inline-block; // height: 100vh; + display: inline-block; padding: 0 2rem; font-family: sans-serif; } @@ -11,70 +11,77 @@ body { margin: 0; //Override } -// Cabezal -header { - .contenedor-logos { - display: inline-block; - height: 1cm; - width: 100%; // padding: 0.5cm 0 0 0; - border-bottom: $borderBottom; +// Header - .contenedor-logo-efector { - margin-top: .05cm; - display: inline-block; - height: 60px; - width: 40%; +.contenedor-logos { + display: inline-block; + height: 1cm; + width: 90%; + // border-bottom: $borderBottom; + margin-left: 0.8cm; - .logo-efector { - height: .75cm; - width: auto; - max-width: 7cm; - } + .contenedor-logo-efector { + margin-top: .05cm; + display: inline-block; + height: 60px; + width: 40%; - .no-logo-efector { - font-size: .20cm; - } + .logo-efector { + height: .75cm; + width: auto; + max-width: 7cm; } - .contenedor-logos-secundarios { - margin-top: .15cm; - float: right; // display: inline-block; // width: 300px; - width: 40%; + .no-logo-efector { + font-size: .20cm; + } + } - .logo-adicional { - filter: grayscale(100%); - -webkit-filter: grayscale(1); - height: .55cm; - width: auto; - } + .contenedor-logos-secundarios { + margin-top: .15cm; + float: right; // display: inline-block; // width: 300px; + width: 40%; - .logo-andes { - float: right; // display: inline-block; // width: 300px; - height: .55cm; - width: auto; // margin-left: 2cm; // float: right; - } + .logo-adicional { + filter: grayscale(100%); + -webkit-filter: grayscale(1); + height: .55cm; + width: auto; + } + + .logo-andes { + float: right; + height: .55cm; + width: auto; } } +} - .contenedor-data-origen { - display: inline-block; - border-bottom: $borderBottom; - width: 100%; +.contenedor-data-origen { + display: inline-block; + width: 100%; + margin-left: 0.6cm; + margin-right: 0.6cm; - .contenedor-principal-data { - display: inline-block; - margin-top: 0.25cm; - margin-bottom: 0.25cm; - width: 50%; + .contenedor-principal-data { + display: inline-block; + margin-top: 0.25cm; + margin-bottom: 0.25cm; + width: 50%; - &:nth-of-type(2) { - // display: inline-block; - float: right; - } + &:nth-of-type(2) { + float: right; } } + + hr { + padding: 0; + width: 90%; + } } +// fin Header + // Globales .contenedor-secundario { display: block; @@ -98,19 +105,16 @@ header { .contenedor-bloque-texto { display: inline-block; margin-right: 1rem; + line-height: 0.35cm; &:last-child { margin-right: 0; } - h6 { - margin: 0; - min-width: 1.25cm; - } } -.w-3\/4 { - width: 60%; +.w-50 { + width: 50%; } .col-3 { @@ -155,7 +159,6 @@ p { } hr { - // border: $borderBottom; margin: 5px 0 5px 0; width: 100%; @@ -185,27 +188,17 @@ hr { // Cuerpo main { - small { - font-weight: 400; - } - // padding: 1rem 0; .contenedor-concepto { display: inline-block; - padding: 1rem 0; // max-height: 10cm; + padding: 1rem 0; } .contenedor-concepto-data { display: inline-block; width: 100%; - float: left; - - >h3 { - // border-bottom: $borderBottom; - } img { - // float: right; text-align: center; max-width: 5cm; max-height: 5cm; @@ -214,39 +207,61 @@ main { page-break-before:always; page-break-inside:avoid; - // margin-top: 300mm; /*phantomjs renders it on the top of the next page*/ } .tipo-prestacion { font-size: .35cm; - display: block; // height: .5cm; + display: block; width: 5.75cm; font-weight: 900; } .contenedor-informe { + .cabezal-conceptos { - display: inline-block; // height: 8mm; // margin-top: 0.5cm; + display: inline-block; margin-right: 0.25cm; width: 100%; + + &.horizontal .contenedor-bloque-texto { + display: inline-block; + margin-right: 1rem; + line-height: 0.35cm; + + h6 { + margin: 0; + min-width: 1.2cm; + font-size: 10px; + font-weight: lighter !important; + line-height: 0.5cm; + } + + &:last-child { + margin-right: 0; + } + } } + } .registros { display: inline !important; p { - line-height: 2.75mm; + font-size: 12px; + line-height: 0.25cm; font-weight: 900; margin-top: 5px; } small { - font-size: 0.25cm; - font-weight: 400; + font-size: 11px; + font-weight: 100; } - .nivel-1 p:first-child, .nivel-2 p:first-child, .nivel-3 p:first-child { + .nivel-1 p:first-child, + .nivel-2 p:first-child, + .nivel-3 p:first-child { text-transform: capitalize; } @@ -258,7 +273,7 @@ main { margin-left: 0em; } - + .nivel-2:not(:first-child) { margin-left: 1em; width: 100%; @@ -275,22 +290,20 @@ main { } } - + .nivel-3 { margin-left: 2em; } - + .adjunto { padding: .2cm 0; - // border-bottom: 1px solid rgba(0, 0, 0, 0.25); - + small { font-size: 0.25cm; } } .archivo-adjunto { - // float: right; text-align: center; max-width: 5cm; max-height: 5cm; @@ -299,9 +312,9 @@ main { } } -// Footer -footer { - // height: auto; +#last { + page-break-inside: avoid; + margin-top: 12px; } .contenedor-firmas { @@ -324,18 +337,17 @@ footer { } h6 { - line-height: 0.5cm; + line-height: 0.35cm; } } .contenedor-zocalo { - display: inline-block; // padding-bottom: 0.5cm; + display: inline-block; + margin-left: 0.5cm; + margin-right: 0.5cm; - // h6 { - // font-size: 10px; - // } img { - float: left; // margin-right: 1rem; + float: left; &.logo-pdp { height: 1cm; @@ -350,10 +362,6 @@ footer { } } - hr { - margin: 5px 0 5px 0; - } - .contenedor-data-pdp { width: 37%; display: inline-block; @@ -371,24 +379,24 @@ footer { .contenedor-data-impresion, .contenedor-data-validacion, .contenedor-data-organizacion { - // display: inline-block; + float: right; max-width: 2.25cm; - margin-left: 0; // text-align: right; + margin-left: 0; margin-left: 0.25cm; } .contenedor-data-organizacion { text-align: left; } +} - .numeracion { - // display: inline-block; - float: right; - width: auto; - height: auto; - font-size: .2cm; - } +.numeracion { + float: right; + width: auto; + height: auto; + font-size: .2cm; + margin-right: 0.5cm; } .table { @@ -421,7 +429,7 @@ footer { .table tbody tr td { border: 0.03cm solid lightgray; - font-size: 0.25cm; + font-size: .25cm; padding: 0.08cm; margin: 0cm !important; border-spacing: 0; @@ -429,12 +437,12 @@ footer { page-break-after: auto } -.resumen .table thead tr th { - font-size: .20cm !important; +.resumen.table thead tr th { + padding: 0 .2cm 0 .2cm; } -.resumen .table tbody tr td { - font-size: .20cm !important; +.resumen.table tbody tr td { + font-size: .25cm !important; } .marca-de-agua { @@ -448,25 +456,4 @@ footer { -ms-transform: rotate(-43deg); -o-transform: rotate(-43deg); transform: rotate(-43deg); -} - -// Media query -// @media screen and (min-width: 980px) { -// .contenedor-zocalo { -// img { -// &.logo-pdp { -// display: none; -// } -// &.logo-pdp-h { -// display: initial; -// align-self: center; -// width: 100px; -// } -// } -// } -// } -// @media screen and (min-width: 320px) and (max-width: 979px) { -// header .contenedor-logos .contenedor-logos-secundarios { -// // display: none; -// } -// } \ No newline at end of file +} \ No newline at end of file diff --git a/utils/pdf/puppeteer.ts b/utils/pdf/puppeteer.ts new file mode 100644 index 0000000000..34b5bb4070 --- /dev/null +++ b/utils/pdf/puppeteer.ts @@ -0,0 +1,161 @@ +import puppeteer, { Browser, Page, PDFOptions } from 'puppeteer'; +import * as sharp from 'sharp'; + +type ImgOpts = { + maxWidth?: 1600; + quality?: 75; // JPEG/WebP 60-85 + format?: 'jpeg' | 'webp'; +}; + +/* Convierte un stream de imagen a un data URI de JPEG optimizado para web (rotado, redimensionado y comprimido). + De esta manera se puede mostrar en el PDF sin que pese demasiado ni consuma mucha memoria +*/ +export async function streamToJpegDataUri( + stream: NodeJS.ReadableStream, + opts: ImgOpts = {} +): Promise { + const maxWidth = opts.maxWidth ?? 1600; + const quality = opts.quality ?? 75; + + const transformer = sharp() + .rotate() + .resize({ width: maxWidth, withoutEnlargement: true }) + .jpeg({ quality, mozjpeg: true }); + + const buf: Buffer = await new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + transformer.on('data', (c) => chunks.push(c as Buffer)); + transformer.on('end', () => resolve(Buffer.concat(chunks))); + transformer.on('error', reject); + stream.on('error', reject); + stream.pipe(transformer); + }); + + return `data:image/jpeg;base64,${buf.toString('base64')}`; +} + +// -------------------------------------------------------------- + +type PdfOpts = { + format?: 'A4' | 'Letter'; + margin?: { top?: string; right?: string; bottom?: string; left?: string }; + headerTemplate?: string; + footerTemplate?: string; + timeoutMs?: number; + landscape?: boolean; + printBackground?: boolean; + preferCSSPageSize?: boolean; +}; + +let browserPromise: Promise | null = null; + +const POOL_SIZE = 2; + +let initPromise: Promise | null = null; +const freePages: Page[] = []; +const waiters: Array<(page: Page) => void> = []; + +async function getBrowser(): Promise { + if (!browserPromise) { + browserPromise = puppeteer.launch({ + headless: true, + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-dev-shm-usage', + '--disable-gpu', + ], + }); + + process.on('exit', async () => { + try { (await browserPromise!).close(); } catch { } + }); + } + return browserPromise; +} + +async function initPool() { + if (initPromise) { return initPromise; } + + initPromise = (async () => { + const browser = await getBrowser(); + for (let i = 0; i < POOL_SIZE; i++) { + const p = await browser.newPage(); + p.setDefaultTimeout(60_000); + p.setDefaultNavigationTimeout(60_000); + freePages.push(p); + } + })(); + + return initPromise; +} + +// El pool es para evitar abrir y cerrar paginas (que es lo que mas tarda) y para limitar la concurrencia (puppeteer puede consumir mucha memoria) +async function acquirePage(): Promise { + await initPool(); + + if (freePages.length > 0) { + return freePages.pop()!; + } + return new Promise((resolve) => waiters.push(resolve)); +} + +// Cuando se libera una pagina, se resuelve la promesa del siguiente en la cola (si hay) o se agrega a las paginas libres +function releasePage(page: Page) { + const next = waiters.shift(); + if (next) { + next(page); + } else { + freePages.push(page); + } +} + +// evita que se acumulen cosas entre renders y que se consuma mucha memoria +async function hardResetPage(page: Page) { + try { + await page.goto('about:blank', { waitUntil: 'domcontentloaded' }); + } catch { } +} + +let renderCount = 0; + +// reinicia el navegador cada 50 renders para evitar fugas de memoria o acumulacion de procesos +async function restartBrowser() { + if (browserPromise) { + try { (await browserPromise).close(); } catch { } + } + browserPromise = null; + initPromise = null; + freePages.length = 0; +} + +export async function htmlToPdfBuffer(html: string, opts: PdfOpts = {}): Promise { + renderCount++; + if (renderCount % 50 === 0) { + await restartBrowser(); + } + + const page = await acquirePage(); + const timeoutMs = opts.timeoutMs ?? 180_000; + + try { + await page.setContent(html, { waitUntil: 'domcontentloaded', timeout: timeoutMs }); + await new Promise((resolve) => setTimeout(resolve, 300)); + const pdfOptions: PDFOptions = { + format: opts.format || 'A4', + printBackground: true, + preferCSSPageSize: true, + margin: opts.margin, + displayHeaderFooter: Boolean(opts.headerTemplate || opts.footerTemplate), + headerTemplate: opts.headerTemplate || '', + footerTemplate: opts.footerTemplate || '', + landscape: opts.landscape || false + }; + + const pdfBytes = await page.pdf(pdfOptions); + return Buffer.from(pdfBytes); + } finally { + await hardResetPage(page); + releasePage(page); + } +}

-
Días de funcionamiento del servicio
+
+ Días de funcionamiento del servicio -
Promedio diario de camas disponibles
+
+ Promedio diario de camas disponibles -
Promedio diario de paciente día
+
+ Promedio diario de paciente día -
Tasa de mortalidad hospitalaria
+
+ Tasa de mortalidad hospitalaria -
Promedio de permanencia
+
+ Promedio de permanencia -
Giro Cama
+
+ Giro Cama -
Promedio días de estada
+
+ Promedio días de estada