@shad0wz7/nestjs-pdf 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -5
- package/dist/index.cjs +519 -176
- package/dist/index.d.cts +142 -88
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +142 -88
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +509 -167
- package/dist/index.mjs.map +1 -1
- package/package.json +35 -25
package/dist/index.cjs
CHANGED
|
@@ -3,14 +3,12 @@ let node_path = require("node:path");
|
|
|
3
3
|
let _nestjs_common = require("@nestjs/common");
|
|
4
4
|
let pdf_lib = require("pdf-lib");
|
|
5
5
|
let deepmerge_ts = require("deepmerge-ts");
|
|
6
|
-
let node_dns_promises = require("node:dns/promises");
|
|
7
6
|
let node_fs = require("node:fs");
|
|
7
|
+
let node_dns_promises = require("node:dns/promises");
|
|
8
8
|
let node_net = require("node:net");
|
|
9
9
|
let node_url = require("node:url");
|
|
10
|
-
let puppeteer = require("puppeteer");
|
|
11
|
-
let _puppeteer_browsers = require("@puppeteer/browsers");
|
|
12
10
|
let node_module = require("node:module");
|
|
13
|
-
|
|
11
|
+
// src/exceptions/nestjs-pdf.exception.ts
|
|
14
12
|
let NestjsPdfErrorCode = /* @__PURE__ */ function(NestjsPdfErrorCode) {
|
|
15
13
|
NestjsPdfErrorCode["ENGINE_NOT_AVAILABLE"] = "ENGINE_NOT_AVAILABLE";
|
|
16
14
|
NestjsPdfErrorCode["TEMPLATE_CONFIGURATION_ERROR"] = "TEMPLATE_CONFIGURATION_ERROR";
|
|
@@ -21,6 +19,7 @@ let NestjsPdfErrorCode = /* @__PURE__ */ function(NestjsPdfErrorCode) {
|
|
|
21
19
|
NestjsPdfErrorCode["SIGNATURE_DEPENDENCY_ERROR"] = "SIGNATURE_DEPENDENCY_ERROR";
|
|
22
20
|
NestjsPdfErrorCode["SIGNATURE_PLACEMENT_ERROR"] = "SIGNATURE_PLACEMENT_ERROR";
|
|
23
21
|
NestjsPdfErrorCode["WATERMARK_ERROR"] = "WATERMARK_ERROR";
|
|
22
|
+
NestjsPdfErrorCode["RENDERER_CONFIGURATION_ERROR"] = "RENDERER_CONFIGURATION_ERROR";
|
|
24
23
|
return NestjsPdfErrorCode;
|
|
25
24
|
}({});
|
|
26
25
|
var NestjsPdfException = class extends Error {
|
|
@@ -29,46 +28,43 @@ var NestjsPdfException = class extends Error {
|
|
|
29
28
|
this.name = this.constructor.name;
|
|
30
29
|
}
|
|
31
30
|
};
|
|
32
|
-
|
|
33
|
-
//#region src/exceptions/browser-installation.exception.ts
|
|
31
|
+
// src/exceptions/browser-installation.exception.ts
|
|
34
32
|
var BrowserInstallationException = class extends NestjsPdfException {
|
|
35
33
|
code = "BROWSER_INSTALLATION_ERROR";
|
|
36
34
|
};
|
|
37
|
-
|
|
38
|
-
//#region src/exceptions/browser-unavailable.exception.ts
|
|
35
|
+
// src/exceptions/browser-unavailable.exception.ts
|
|
39
36
|
var BrowserUnavailableException = class extends NestjsPdfException {
|
|
40
37
|
code = "BROWSER_UNAVAILABLE";
|
|
41
38
|
};
|
|
42
|
-
|
|
43
|
-
//#region src/exceptions/engine-not-available.exception.ts
|
|
39
|
+
// src/exceptions/engine-not-available.exception.ts
|
|
44
40
|
var EngineNotAvailableException = class extends NestjsPdfException {
|
|
45
41
|
code = "ENGINE_NOT_AVAILABLE";
|
|
46
42
|
constructor(engineName, packageName, options) {
|
|
47
43
|
super(packageName ? `${engineName} engine is not available: the '${packageName}' package is not installed. Run \`npm install ${packageName}\` to use it.` : `${engineName} service is not available. If the problem persists, open an issue in the repo.`, options);
|
|
48
44
|
}
|
|
49
45
|
};
|
|
50
|
-
|
|
51
|
-
//#region src/exceptions/pdf-generation.exception.ts
|
|
46
|
+
// src/exceptions/pdf-generation.exception.ts
|
|
52
47
|
var PdfGenerationException = class extends NestjsPdfException {
|
|
53
48
|
code = "PDF_GENERATION_ERROR";
|
|
54
49
|
};
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
// src/exceptions/renderer-configuration.exception.ts
|
|
51
|
+
/** The PDF provider is misconfigured, or asked for an option it does not support. */
|
|
52
|
+
var RendererConfigurationException = class extends NestjsPdfException {
|
|
53
|
+
code = "RENDERER_CONFIGURATION_ERROR";
|
|
54
|
+
};
|
|
55
|
+
// src/exceptions/signature-dependency.exception.ts
|
|
57
56
|
var SignatureDependencyException = class extends NestjsPdfException {
|
|
58
57
|
code = "SIGNATURE_DEPENDENCY_ERROR";
|
|
59
58
|
};
|
|
60
|
-
|
|
61
|
-
//#region src/exceptions/signature-placement.exception.ts
|
|
59
|
+
// src/exceptions/signature-placement.exception.ts
|
|
62
60
|
var SignaturePlacementException = class extends NestjsPdfException {
|
|
63
61
|
code = "SIGNATURE_PLACEMENT_ERROR";
|
|
64
62
|
};
|
|
65
|
-
|
|
66
|
-
//#region src/exceptions/template-configuration.exception.ts
|
|
63
|
+
// src/exceptions/template-configuration.exception.ts
|
|
67
64
|
var TemplateConfigurationException = class extends NestjsPdfException {
|
|
68
65
|
code = "TEMPLATE_CONFIGURATION_ERROR";
|
|
69
66
|
};
|
|
70
|
-
|
|
71
|
-
//#region src/exceptions/template-render.exception.ts
|
|
67
|
+
// src/exceptions/template-render.exception.ts
|
|
72
68
|
var TemplateRenderException = class extends NestjsPdfException {
|
|
73
69
|
engine;
|
|
74
70
|
code = "TEMPLATE_RENDER_ERROR";
|
|
@@ -77,13 +73,11 @@ var TemplateRenderException = class extends NestjsPdfException {
|
|
|
77
73
|
this.engine = engine;
|
|
78
74
|
}
|
|
79
75
|
};
|
|
80
|
-
|
|
81
|
-
//#region src/exceptions/watermark.exception.ts
|
|
76
|
+
// src/exceptions/watermark.exception.ts
|
|
82
77
|
var WatermarkException = class extends NestjsPdfException {
|
|
83
78
|
code = "WATERMARK_ERROR";
|
|
84
79
|
};
|
|
85
|
-
|
|
86
|
-
//#region src/helpers/getRelativePath.helper.ts
|
|
80
|
+
// src/helpers/getRelativePath.helper.ts
|
|
87
81
|
/**
|
|
88
82
|
* Get the relative path to a value from the module directory.
|
|
89
83
|
* @param moduleDir the path of the module, typically __dirname
|
|
@@ -97,8 +91,7 @@ function getRelativePathToValue(moduleDir, relativeToModule) {
|
|
|
97
91
|
const fullTemplatePath = (0, node_path.resolve)(moduleDir, relativeToModule);
|
|
98
92
|
return (0, node_path.relative)(process.cwd(), fullTemplatePath);
|
|
99
93
|
}
|
|
100
|
-
|
|
101
|
-
//#region src/helpers/signature.helper.ts
|
|
94
|
+
// src/helpers/signature.helper.ts
|
|
102
95
|
let pdfjsPromise;
|
|
103
96
|
async function loadPdfjs() {
|
|
104
97
|
if (!pdfjsPromise) try {
|
|
@@ -241,8 +234,7 @@ async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor",
|
|
|
241
234
|
}
|
|
242
235
|
return await pdfDoc.save();
|
|
243
236
|
}
|
|
244
|
-
|
|
245
|
-
//#region src/helpers/watermark.helper.ts
|
|
237
|
+
// src/helpers/watermark.helper.ts
|
|
246
238
|
const DEFAULT_OPACITY = .15;
|
|
247
239
|
const DEFAULT_ROTATION = 45;
|
|
248
240
|
const DEFAULT_FONT_SIZE = 60;
|
|
@@ -385,8 +377,7 @@ async function addWatermark(pdf, options) {
|
|
|
385
377
|
throw new WatermarkException(`Failed to add watermark: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
386
378
|
}
|
|
387
379
|
}
|
|
388
|
-
|
|
389
|
-
//#region node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
380
|
+
// node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
390
381
|
var Node = class {
|
|
391
382
|
value;
|
|
392
383
|
next;
|
|
@@ -443,8 +434,7 @@ var Queue = class {
|
|
|
443
434
|
while (this.#head) yield this.dequeue();
|
|
444
435
|
}
|
|
445
436
|
};
|
|
446
|
-
|
|
447
|
-
//#region node_modules/.pnpm/p-limit@7.3.3/node_modules/p-limit/index.js
|
|
437
|
+
// node_modules/.pnpm/p-limit@7.3.3/node_modules/p-limit/index.js
|
|
448
438
|
function pLimit(concurrency) {
|
|
449
439
|
let rejectOnClear = false;
|
|
450
440
|
if (typeof concurrency === "object") ({concurrency, rejectOnClear = false} = concurrency);
|
|
@@ -522,14 +512,296 @@ function pLimit(concurrency) {
|
|
|
522
512
|
function validateConcurrency(concurrency) {
|
|
523
513
|
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
|
|
524
514
|
}
|
|
525
|
-
|
|
526
|
-
//#region src/helpers/deepMergePdfparams.ts
|
|
515
|
+
// src/helpers/deepMergePdfparams.ts
|
|
527
516
|
function mergePuppeteerParameters(defaults, overrides) {
|
|
528
517
|
if (!overrides) return { ...defaults };
|
|
529
518
|
return (0, deepmerge_ts.deepmerge)(defaults, overrides);
|
|
530
519
|
}
|
|
531
|
-
|
|
532
|
-
|
|
520
|
+
// src/helpers/tokens.ts
|
|
521
|
+
const PDF_PARAMETERS = "PDF_PARAMETERS";
|
|
522
|
+
// src/renderers/pdf-renderer.interface.ts
|
|
523
|
+
const PDF_RENDERER = "PDF_RENDERER";
|
|
524
|
+
// src/renderers/http.utils.ts
|
|
525
|
+
const MAX_ERROR_BODY_LENGTH = 500;
|
|
526
|
+
/** Builds a `PdfGenerationException` from a failed HTTP response, body included. */
|
|
527
|
+
async function httpError(provider, response) {
|
|
528
|
+
let body = "";
|
|
529
|
+
try {
|
|
530
|
+
body = (await response.text()).trim().slice(0, MAX_ERROR_BODY_LENGTH);
|
|
531
|
+
} catch {}
|
|
532
|
+
return new PdfGenerationException(`${provider} responded with HTTP ${response.status}${body ? `: ${body}` : ""}`);
|
|
533
|
+
}
|
|
534
|
+
/** Remote providers render on another machine: the local request guard cannot run there. */
|
|
535
|
+
function assertNoRequestGuard(provider, options, hint) {
|
|
536
|
+
if (options.security) throw new RendererConfigurationException(`The 'security' option is only supported by the puppeteer provider, not by ${provider}. ${hint}`);
|
|
537
|
+
}
|
|
538
|
+
function requireNonEmpty(value, name, provider) {
|
|
539
|
+
if (!value?.trim()) throw new RendererConfigurationException(`The ${provider} provider requires a non-empty '${name}'`);
|
|
540
|
+
return value;
|
|
541
|
+
}
|
|
542
|
+
// src/renderers/pdf-options.mapper.ts
|
|
543
|
+
/** Paper sizes in inches, as Puppeteer defines them. */
|
|
544
|
+
const PAPER_FORMATS = {
|
|
545
|
+
letter: {
|
|
546
|
+
width: 8.5,
|
|
547
|
+
height: 11
|
|
548
|
+
},
|
|
549
|
+
legal: {
|
|
550
|
+
width: 8.5,
|
|
551
|
+
height: 14
|
|
552
|
+
},
|
|
553
|
+
tabloid: {
|
|
554
|
+
width: 11,
|
|
555
|
+
height: 17
|
|
556
|
+
},
|
|
557
|
+
ledger: {
|
|
558
|
+
width: 17,
|
|
559
|
+
height: 11
|
|
560
|
+
},
|
|
561
|
+
a0: {
|
|
562
|
+
width: 33.1102,
|
|
563
|
+
height: 46.811
|
|
564
|
+
},
|
|
565
|
+
a1: {
|
|
566
|
+
width: 23.3858,
|
|
567
|
+
height: 33.1102
|
|
568
|
+
},
|
|
569
|
+
a2: {
|
|
570
|
+
width: 16.5354,
|
|
571
|
+
height: 23.3858
|
|
572
|
+
},
|
|
573
|
+
a3: {
|
|
574
|
+
width: 11.6929,
|
|
575
|
+
height: 16.5354
|
|
576
|
+
},
|
|
577
|
+
a4: {
|
|
578
|
+
width: 8.2677,
|
|
579
|
+
height: 11.6929
|
|
580
|
+
},
|
|
581
|
+
a5: {
|
|
582
|
+
width: 5.8268,
|
|
583
|
+
height: 8.2677
|
|
584
|
+
},
|
|
585
|
+
a6: {
|
|
586
|
+
width: 4.1339,
|
|
587
|
+
height: 5.8268
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
const INCHES_PER_UNIT = {
|
|
591
|
+
px: 1 / 96,
|
|
592
|
+
in: 1,
|
|
593
|
+
cm: 1 / 2.54,
|
|
594
|
+
mm: 1 / 25.4
|
|
595
|
+
};
|
|
596
|
+
/**
|
|
597
|
+
* Converts a Puppeteer length (a number of pixels, or a string with a
|
|
598
|
+
* `px`/`in`/`cm`/`mm` unit) to inches.
|
|
599
|
+
*/
|
|
600
|
+
function toInches(value) {
|
|
601
|
+
if (typeof value === "number") return value * INCHES_PER_UNIT.px;
|
|
602
|
+
const match = /^\s*(-?\d*\.?\d+)\s*(px|in|cm|mm)?\s*$/i.exec(value);
|
|
603
|
+
if (!match) throw new RendererConfigurationException(`Invalid length '${value}': expected a number of pixels or a value in px, in, cm or mm`);
|
|
604
|
+
const unit = (match[2] ?? "px").toLowerCase();
|
|
605
|
+
return Number(match[1]) * INCHES_PER_UNIT[unit];
|
|
606
|
+
}
|
|
607
|
+
function formatInches(inches) {
|
|
608
|
+
return String(Math.round(inches * 1e4) / 1e4);
|
|
609
|
+
}
|
|
610
|
+
function resolvePrintLayout(pdfOptions) {
|
|
611
|
+
let width;
|
|
612
|
+
let height;
|
|
613
|
+
if (pdfOptions.width !== void 0 || pdfOptions.height !== void 0) {
|
|
614
|
+
const fallback = PAPER_FORMATS.letter;
|
|
615
|
+
width = pdfOptions.width === void 0 ? fallback.width : toInches(pdfOptions.width);
|
|
616
|
+
height = pdfOptions.height === void 0 ? fallback.height : toInches(pdfOptions.height);
|
|
617
|
+
} else {
|
|
618
|
+
const formatName = (pdfOptions.format ?? "letter").toLowerCase();
|
|
619
|
+
const format = PAPER_FORMATS[formatName];
|
|
620
|
+
if (!format) throw new RendererConfigurationException(`Unknown paper format '${pdfOptions.format}'`);
|
|
621
|
+
({width, height} = format);
|
|
622
|
+
}
|
|
623
|
+
const margin = {};
|
|
624
|
+
for (const side of [
|
|
625
|
+
"top",
|
|
626
|
+
"right",
|
|
627
|
+
"bottom",
|
|
628
|
+
"left"
|
|
629
|
+
]) {
|
|
630
|
+
const value = pdfOptions.margin?.[side];
|
|
631
|
+
if (value !== void 0) margin[side] = toInches(value);
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
width,
|
|
635
|
+
height,
|
|
636
|
+
margin
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
function toHtmlDocument(template) {
|
|
640
|
+
return /<html[\s>]/i.test(template) ? template : `<!DOCTYPE html><html><head></head><body>${template}</body></html>`;
|
|
641
|
+
}
|
|
642
|
+
function toGotenbergForm(pdfOptions) {
|
|
643
|
+
const { width, height, margin } = resolvePrintLayout(pdfOptions);
|
|
644
|
+
const fields = {
|
|
645
|
+
paperWidth: formatInches(width),
|
|
646
|
+
paperHeight: formatInches(height),
|
|
647
|
+
marginTop: formatInches(margin.top ?? 0),
|
|
648
|
+
marginRight: formatInches(margin.right ?? 0),
|
|
649
|
+
marginBottom: formatInches(margin.bottom ?? 0),
|
|
650
|
+
marginLeft: formatInches(margin.left ?? 0),
|
|
651
|
+
emulatedMediaType: "screen",
|
|
652
|
+
skipNetworkIdleEvent: "false"
|
|
653
|
+
};
|
|
654
|
+
if (pdfOptions.landscape !== void 0) fields.landscape = String(pdfOptions.landscape);
|
|
655
|
+
if (pdfOptions.printBackground !== void 0) fields.printBackground = String(pdfOptions.printBackground);
|
|
656
|
+
if (pdfOptions.omitBackground !== void 0) fields.omitBackground = String(pdfOptions.omitBackground);
|
|
657
|
+
if (pdfOptions.scale !== void 0) fields.scale = String(pdfOptions.scale);
|
|
658
|
+
if (pdfOptions.pageRanges) fields.nativePageRanges = pdfOptions.pageRanges;
|
|
659
|
+
if (pdfOptions.preferCSSPageSize !== void 0) fields.preferCssPageSize = String(pdfOptions.preferCSSPageSize);
|
|
660
|
+
if (pdfOptions.tagged !== void 0) fields.generateTaggedPdf = String(pdfOptions.tagged);
|
|
661
|
+
if (pdfOptions.outline !== void 0) fields.generateDocumentOutline = String(pdfOptions.outline);
|
|
662
|
+
const files = {};
|
|
663
|
+
if (pdfOptions.displayHeaderFooter) {
|
|
664
|
+
if (pdfOptions.headerTemplate) files["header.html"] = toHtmlDocument(pdfOptions.headerTemplate);
|
|
665
|
+
if (pdfOptions.footerTemplate) files["footer.html"] = toHtmlDocument(pdfOptions.footerTemplate);
|
|
666
|
+
}
|
|
667
|
+
return {
|
|
668
|
+
fields,
|
|
669
|
+
files
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
function toApi2PdfOptions(pdfOptions) {
|
|
673
|
+
const { width, height, margin } = resolvePrintLayout(pdfOptions);
|
|
674
|
+
const options = {
|
|
675
|
+
width: `${formatInches(width)}in`,
|
|
676
|
+
height: `${formatInches(height)}in`,
|
|
677
|
+
marginTop: `${formatInches(margin.top ?? 0)}in`,
|
|
678
|
+
marginRight: `${formatInches(margin.right ?? 0)}in`,
|
|
679
|
+
marginBottom: `${formatInches(margin.bottom ?? 0)}in`,
|
|
680
|
+
marginLeft: `${formatInches(margin.left ?? 0)}in`,
|
|
681
|
+
usePrintCss: false
|
|
682
|
+
};
|
|
683
|
+
for (const key of [
|
|
684
|
+
"landscape",
|
|
685
|
+
"printBackground",
|
|
686
|
+
"omitBackground",
|
|
687
|
+
"scale",
|
|
688
|
+
"pageRanges",
|
|
689
|
+
"displayHeaderFooter",
|
|
690
|
+
"headerTemplate",
|
|
691
|
+
"footerTemplate"
|
|
692
|
+
]) if (pdfOptions[key] !== void 0) options[key] = pdfOptions[key];
|
|
693
|
+
return options;
|
|
694
|
+
}
|
|
695
|
+
// src/renderers/api2pdf.renderer.ts
|
|
696
|
+
const PROVIDER$1 = "Api2Pdf";
|
|
697
|
+
const DEFAULT_BASE_URL = "https://v2.api2pdf.com";
|
|
698
|
+
const ROUTE$1 = "/chrome/pdf/html";
|
|
699
|
+
function isApi2Pdf(data) {
|
|
700
|
+
return typeof data === "object" && data !== null && ("Success" in data || "Error" in data || "FileUrl" in data);
|
|
701
|
+
}
|
|
702
|
+
var Api2PdfRenderer = class {
|
|
703
|
+
#endpoint;
|
|
704
|
+
#headers;
|
|
705
|
+
constructor(provider) {
|
|
706
|
+
const apiKey = requireNonEmpty(provider.apiKey, "apiKey", PROVIDER$1);
|
|
707
|
+
const baseUrl = requireNonEmpty(provider.baseUrl ?? DEFAULT_BASE_URL, "baseUrl", PROVIDER$1).replace(/\/+$/, "");
|
|
708
|
+
this.#endpoint = `${baseUrl}${ROUTE$1}?outputBinary=true`;
|
|
709
|
+
this.#headers = {
|
|
710
|
+
...provider.headers,
|
|
711
|
+
Authorization: apiKey,
|
|
712
|
+
"Content-Type": "application/json",
|
|
713
|
+
Accept: "application/pdf, application/json"
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
async render(html, options, signal) {
|
|
717
|
+
assertNoRequestGuard(PROVIDER$1, options, "Only render trusted HTML with a remote provider.");
|
|
718
|
+
const body = {
|
|
719
|
+
html,
|
|
720
|
+
inline: false,
|
|
721
|
+
options: {
|
|
722
|
+
...toApi2PdfOptions(options.pdfOptions ?? { format: "A4" }),
|
|
723
|
+
...options.api2pdfOptions?.options
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
if (options.api2pdfOptions?.fileName) body.fileName = options.api2pdfOptions.fileName;
|
|
727
|
+
const response = await fetch(this.#endpoint, {
|
|
728
|
+
method: "POST",
|
|
729
|
+
headers: this.#headers,
|
|
730
|
+
body: JSON.stringify(body),
|
|
731
|
+
signal
|
|
732
|
+
});
|
|
733
|
+
if (!response.ok) throw await httpError(PROVIDER$1, response);
|
|
734
|
+
if (!response.headers.get("content-type")?.includes("application/json")) return new Uint8Array(await response.arrayBuffer());
|
|
735
|
+
const result = await response.json();
|
|
736
|
+
if (!isApi2Pdf(result)) throw new PdfGenerationException(`${PROVIDER$1} returned an unexpected response: ${JSON.stringify(result)}`);
|
|
737
|
+
if (result.Success === false || !result.FileUrl) throw new PdfGenerationException(`${PROVIDER$1} could not generate the PDF: ${result.Error ?? "no file returned"}`);
|
|
738
|
+
const file = await fetch(result.FileUrl, { signal });
|
|
739
|
+
if (!file.ok) throw await httpError(PROVIDER$1, file);
|
|
740
|
+
return new Uint8Array(await file.arrayBuffer());
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
// src/renderers/gotenberg.renderer.ts
|
|
744
|
+
const PROVIDER = "Gotenberg";
|
|
745
|
+
const ROUTE = "/forms/chromium/convert/html";
|
|
746
|
+
var GotenbergRenderer = class {
|
|
747
|
+
#endpoint;
|
|
748
|
+
#headers;
|
|
749
|
+
constructor(provider) {
|
|
750
|
+
const url = requireNonEmpty(provider.url, "url", PROVIDER);
|
|
751
|
+
this.#endpoint = `${url.replace(/\/+$/, "")}${ROUTE}`;
|
|
752
|
+
this.#headers = { ...provider.headers };
|
|
753
|
+
if (provider.basicAuth) {
|
|
754
|
+
const { username, password } = provider.basicAuth;
|
|
755
|
+
this.#headers.Authorization = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
async render(html, options, signal) {
|
|
759
|
+
assertNoRequestGuard(PROVIDER, options, "Restrict outbound requests on the Gotenberg server instead, with '--chromium-allow-list' / '--chromium-deny-list'.");
|
|
760
|
+
const { fields, files } = toGotenbergForm(options.pdfOptions ?? { format: "A4" });
|
|
761
|
+
const form = new FormData();
|
|
762
|
+
form.append("files", new Blob([html], { type: "text/html" }), "index.html");
|
|
763
|
+
for (const [name, content] of Object.entries(files)) form.append("files", new Blob([content], { type: "text/html" }), name);
|
|
764
|
+
for (const asset of options.gotenbergOptions?.assets ?? []) form.append("files", new Blob([asset.content], { type: asset.contentType ?? "application/octet-stream" }), asset.filename);
|
|
765
|
+
const allFields = {
|
|
766
|
+
...fields,
|
|
767
|
+
...options.gotenbergOptions?.formFields
|
|
768
|
+
};
|
|
769
|
+
for (const [name, value] of Object.entries(allFields)) form.append(name, value);
|
|
770
|
+
const response = await fetch(this.#endpoint, {
|
|
771
|
+
method: "POST",
|
|
772
|
+
headers: this.#headers,
|
|
773
|
+
body: form,
|
|
774
|
+
signal
|
|
775
|
+
});
|
|
776
|
+
if (!response.ok) throw await httpError(PROVIDER, response);
|
|
777
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
// src/puppeteer/libs/loadPuppeteer.utils.ts
|
|
781
|
+
function isMissingPackage(error, packageName) {
|
|
782
|
+
const { code, message } = error;
|
|
783
|
+
return (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") && typeof message === "string" && message.includes(`'${packageName}'`);
|
|
784
|
+
}
|
|
785
|
+
/** Imports an optional peer dependency, turning "not installed" into a clear exception. */
|
|
786
|
+
async function loadOptional(packageName, importer) {
|
|
787
|
+
try {
|
|
788
|
+
return await importer();
|
|
789
|
+
} catch (error) {
|
|
790
|
+
if (isMissingPackage(error, packageName)) throw new EngineNotAvailableException("Puppeteer", packageName, { cause: error });
|
|
791
|
+
throw error;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Puppeteer is an optional peer dependency, only needed by the `puppeteer`
|
|
796
|
+
* provider: it is imported on first use, never when the library loads.
|
|
797
|
+
*/
|
|
798
|
+
function loadPuppeteer() {
|
|
799
|
+
return loadOptional("puppeteer", () => import("puppeteer"));
|
|
800
|
+
}
|
|
801
|
+
function loadPuppeteerBrowsers() {
|
|
802
|
+
return loadOptional("@puppeteer/browsers", () => import("@puppeteer/browsers"));
|
|
803
|
+
}
|
|
804
|
+
// src/helpers/request-guard.helper.ts
|
|
533
805
|
const blockedRanges = new node_net.BlockList();
|
|
534
806
|
for (const [address, prefix] of [
|
|
535
807
|
["0.0.0.0", 8],
|
|
@@ -657,8 +929,9 @@ function describe(rawUrl) {
|
|
|
657
929
|
* and closes the pop-ups a script could open to escape the filter.
|
|
658
930
|
*/
|
|
659
931
|
async function installRequestGuard(context, page, options) {
|
|
932
|
+
const { TargetType } = await loadPuppeteer();
|
|
660
933
|
context.on("targetcreated", (target) => {
|
|
661
|
-
if (target.type() ===
|
|
934
|
+
if (target.type() === TargetType.PAGE && target.opener()) target.page().then((popup) => popup?.close()).catch(() => void 0);
|
|
662
935
|
});
|
|
663
936
|
if (options.javascriptEnabled === false) await page.setJavaScriptEnabled(false);
|
|
664
937
|
await page.setRequestInterception(true);
|
|
@@ -676,31 +949,162 @@ async function installRequestGuard(context, page, options) {
|
|
|
676
949
|
})().catch(() => void 0);
|
|
677
950
|
});
|
|
678
951
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
952
|
+
// src/renderers/puppeteer.renderer.ts
|
|
953
|
+
const DEFAULT_ARGS = [
|
|
954
|
+
"--autoplay-policy=user-gesture-required",
|
|
955
|
+
"--disable-background-networking",
|
|
956
|
+
"--disable-background-timer-throttling",
|
|
957
|
+
"--disable-backgrounding-occluded-windows",
|
|
958
|
+
"--disable-breakpad",
|
|
959
|
+
"--disable-client-side-phishing-detection",
|
|
960
|
+
"--disable-component-update",
|
|
961
|
+
"--disable-default-apps",
|
|
962
|
+
"--disable-dev-shm-usage",
|
|
963
|
+
"--disable-domain-reliability",
|
|
964
|
+
"--disable-extensions",
|
|
965
|
+
"--disable-features=AudioServiceOutOfProcess",
|
|
966
|
+
"--disable-hang-monitor",
|
|
967
|
+
"--disable-ipc-flooding-protection",
|
|
968
|
+
"--disable-notifications",
|
|
969
|
+
"--disable-offer-store-unmasked-wallet-cards",
|
|
970
|
+
"--disable-print-preview",
|
|
971
|
+
"--disable-prompt-on-repost",
|
|
972
|
+
"--disable-renderer-backgrounding",
|
|
973
|
+
"--disable-setuid-sandbox",
|
|
974
|
+
"--disable-speech-api",
|
|
975
|
+
"--disable-sync",
|
|
976
|
+
"--hide-scrollbars",
|
|
977
|
+
"--ignore-gpu-blacklist",
|
|
978
|
+
"--metrics-recording-only",
|
|
979
|
+
"--mute-audio",
|
|
980
|
+
"--no-default-browser-check",
|
|
981
|
+
"--no-first-run",
|
|
982
|
+
"--no-pings",
|
|
983
|
+
"--password-store=basic",
|
|
984
|
+
"--use-gl=swiftshader",
|
|
985
|
+
"--use-mock-keychain",
|
|
986
|
+
"--disable-accelerated-2d-canvas",
|
|
987
|
+
"--no-zygote",
|
|
988
|
+
"--disable-gpu"
|
|
989
|
+
];
|
|
990
|
+
const PDF_OPTION_KEYS = {
|
|
991
|
+
scale: true,
|
|
992
|
+
displayHeaderFooter: true,
|
|
993
|
+
headerTemplate: true,
|
|
994
|
+
footerTemplate: true,
|
|
995
|
+
printBackground: true,
|
|
996
|
+
landscape: true,
|
|
997
|
+
pageRanges: true,
|
|
998
|
+
format: true,
|
|
999
|
+
width: true,
|
|
1000
|
+
height: true,
|
|
1001
|
+
preferCSSPageSize: true,
|
|
1002
|
+
margin: true,
|
|
1003
|
+
path: true,
|
|
1004
|
+
omitBackground: true,
|
|
1005
|
+
tagged: true,
|
|
1006
|
+
outline: true,
|
|
1007
|
+
timeout: true,
|
|
1008
|
+
waitForFonts: true
|
|
1009
|
+
};
|
|
1010
|
+
function toPuppeteerPdfOptions(options) {
|
|
1011
|
+
if (!options) return { format: "A4" };
|
|
1012
|
+
const invalidKeys = Object.keys(options).filter((key) => !Object.hasOwn(PDF_OPTION_KEYS, key));
|
|
1013
|
+
if (invalidKeys.length > 0) throw new RendererConfigurationException(`Invalid PDF options: ${invalidKeys.join(", ")}. Please check the documentation for valid options.`);
|
|
1014
|
+
return options;
|
|
1015
|
+
}
|
|
1016
|
+
var PuppeteerRenderer = class {
|
|
1017
|
+
#browserService;
|
|
1018
|
+
constructor(browserService) {
|
|
1019
|
+
this.#browserService = browserService;
|
|
1020
|
+
}
|
|
1021
|
+
async render(html, options, signal) {
|
|
1022
|
+
if (options.chromiumRevision !== void 0) _nestjs_common.Logger.warn("Using `chromiumRevision` is no longer supported since the puppeteer update.");
|
|
1023
|
+
const pdfOptions = toPuppeteerPdfOptions(options.pdfOptions);
|
|
1024
|
+
const headless = options.headless ?? true;
|
|
1025
|
+
const executablePath = options.executablePath || void 0;
|
|
1026
|
+
const args = options.extraPuppeteerArgs || DEFAULT_ARGS;
|
|
1027
|
+
let context = null;
|
|
1028
|
+
let closing;
|
|
1029
|
+
const onAbort = () => {
|
|
1030
|
+
if (!context) return;
|
|
1031
|
+
closing = context.close();
|
|
1032
|
+
closing.catch(() => void 0);
|
|
1033
|
+
};
|
|
1034
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1035
|
+
try {
|
|
1036
|
+
context = await this.#browserService.createContext(args, headless, executablePath);
|
|
1037
|
+
signal?.throwIfAborted();
|
|
1038
|
+
const page = await context.newPage();
|
|
1039
|
+
if (options.security) await installRequestGuard(context, page, options.security);
|
|
1040
|
+
await page.setContent(html, { waitUntil: "domcontentloaded" });
|
|
1041
|
+
await page.emulateMediaType("screen");
|
|
1042
|
+
await page.waitForNetworkIdle({
|
|
1043
|
+
idleTime: 500,
|
|
1044
|
+
timeout: 3e4
|
|
1045
|
+
});
|
|
1046
|
+
/* v8 ignore next */
|
|
1047
|
+
await page.evaluate(() => document.fonts.ready);
|
|
1048
|
+
return await page.pdf(pdfOptions);
|
|
1049
|
+
} finally {
|
|
1050
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1051
|
+
if (context) try {
|
|
1052
|
+
if (closing) await closing;
|
|
1053
|
+
else await context.close();
|
|
1054
|
+
} catch (error) {
|
|
1055
|
+
_nestjs_common.Logger.error(error);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
// src/renderers/create-renderer.ts
|
|
1061
|
+
/** True when the PDFs are printed by the local Chromium (the default). */
|
|
1062
|
+
function usesPuppeteer(params) {
|
|
1063
|
+
return (params.provider?.type ?? "puppeteer") === "puppeteer";
|
|
1064
|
+
}
|
|
1065
|
+
function createPdfRenderer(params, browserService) {
|
|
1066
|
+
const provider = params.provider ?? { type: "puppeteer" };
|
|
1067
|
+
switch (provider.type) {
|
|
1068
|
+
case "puppeteer": return new PuppeteerRenderer(browserService);
|
|
1069
|
+
case "gotenberg": return new GotenbergRenderer(provider);
|
|
1070
|
+
case "api2pdf": return new Api2PdfRenderer(provider);
|
|
1071
|
+
default: throw new RendererConfigurationException(`Unknown PDF provider '${String(provider.type)}': expected 'puppeteer', 'gotenberg' or 'api2pdf'`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
// src/puppeteer/libs/enum.utils.ts
|
|
1075
|
+
/**
|
|
1076
|
+
* Converts a string value to an enum member, throwing a RendererConfigurationException if the value is not a valid member of the enum.
|
|
1077
|
+
* @param enumObject
|
|
1078
|
+
* @param value
|
|
1079
|
+
* @param label
|
|
1080
|
+
* @throws RendererConfigurationException
|
|
1081
|
+
*/
|
|
1082
|
+
function toEnumMember(enumObject, value, label) {
|
|
1083
|
+
const members = Object.values(enumObject);
|
|
1084
|
+
const isMember = (candidate) => candidate === value;
|
|
1085
|
+
const member = members.find(isMember);
|
|
1086
|
+
if (member === void 0) throw new RendererConfigurationException(`Unsupported ${label} '${value}': expected one of ${members.map((m) => `'${m}'`).join(", ")}`);
|
|
1087
|
+
return member;
|
|
1088
|
+
}
|
|
1089
|
+
// \0@oxc-project+runtime@0.156.0/helpers/esm/decorateMetadata.js
|
|
684
1090
|
function __decorateMetadata(k, v) {
|
|
685
1091
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
686
1092
|
}
|
|
687
|
-
|
|
688
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorateParam.js
|
|
1093
|
+
// \0@oxc-project+runtime@0.156.0/helpers/esm/decorateParam.js
|
|
689
1094
|
function __decorateParam(paramIndex, decorator) {
|
|
690
1095
|
return function(target, key) {
|
|
691
1096
|
decorator(target, key, paramIndex);
|
|
692
1097
|
};
|
|
693
1098
|
}
|
|
694
|
-
|
|
695
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorate.js
|
|
1099
|
+
// \0@oxc-project+runtime@0.156.0/helpers/esm/decorate.js
|
|
696
1100
|
function __decorate(decorators, target, key, desc) {
|
|
697
1101
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
698
1102
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
699
1103
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
700
1104
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
701
1105
|
}
|
|
702
|
-
|
|
703
|
-
|
|
1106
|
+
// src/puppeteer/browser/browser.service.ts
|
|
1107
|
+
const DEFAULT_BROWSER = "chromium";
|
|
704
1108
|
async function sleep(ms) {
|
|
705
1109
|
await new Promise((r) => setTimeout(r, ms));
|
|
706
1110
|
}
|
|
@@ -752,7 +1156,7 @@ let BrowserService = class BrowserService {
|
|
|
752
1156
|
} catch (error) {
|
|
753
1157
|
_nestjs_common.Logger.warn(`Failed to close browser on module destroy: ${error instanceof Error ? error.message : String(error)}`);
|
|
754
1158
|
}
|
|
755
|
-
if (this.#options
|
|
1159
|
+
if (this.#options !== void 0 && usesPuppeteer(this.#options) && this.#options.cleanupBrowserCacheOnExit !== false) await this.#cleanupCacheBestEffort();
|
|
756
1160
|
}
|
|
757
1161
|
/** Wait until no PDF job is in flight, or until the timeout elapses. */
|
|
758
1162
|
async #waitForIdle(timeoutMs) {
|
|
@@ -834,11 +1238,12 @@ let BrowserService = class BrowserService {
|
|
|
834
1238
|
}
|
|
835
1239
|
}
|
|
836
1240
|
async #doInstall(lock) {
|
|
837
|
-
const
|
|
1241
|
+
const { Browser: BrowserEnum, BrowserPlatform, canDownload, detectBrowserPlatform, install, resolveBuildId } = await loadPuppeteerBrowsers();
|
|
1242
|
+
const browser = toEnumMember(BrowserEnum, this.#browser, "browser");
|
|
838
1243
|
const versionTag = this.#browserTag;
|
|
839
|
-
const browserPlatform =
|
|
1244
|
+
const browserPlatform = detectBrowserPlatform() ?? BrowserPlatform.LINUX;
|
|
840
1245
|
let buildId;
|
|
841
|
-
if (this.#buildId === void 0) buildId = await
|
|
1246
|
+
if (this.#buildId === void 0) buildId = await resolveBuildId(browser, browserPlatform, versionTag);
|
|
842
1247
|
else buildId = this.#buildId;
|
|
843
1248
|
_nestjs_common.Logger.log(`Browser ${browser} ${versionTag} build id: ${buildId}`, "NestJsPdf");
|
|
844
1249
|
if (await this.hasBrowserInstalled(browser, buildId)) {
|
|
@@ -853,9 +1258,9 @@ let BrowserService = class BrowserService {
|
|
|
853
1258
|
buildId,
|
|
854
1259
|
baseUrl: this.#options?.browserInstallBaseUrl ?? void 0
|
|
855
1260
|
};
|
|
856
|
-
if (await
|
|
1261
|
+
if (await canDownload(installOption)) {
|
|
857
1262
|
_nestjs_common.Logger.log(`Installing ${installOption.browser} ${installOption.buildId}`, "NestJsPdf");
|
|
858
|
-
const installedBrowser = await
|
|
1263
|
+
const installedBrowser = await install(installOption);
|
|
859
1264
|
if (await this.hasBrowserInstalled(browser, buildId)) {
|
|
860
1265
|
_nestjs_common.Logger.log("Browser installed successfully", "NestJsPdf");
|
|
861
1266
|
if (lock) this.#writeLockFile(browser, buildId);
|
|
@@ -866,10 +1271,7 @@ let BrowserService = class BrowserService {
|
|
|
866
1271
|
return null;
|
|
867
1272
|
}
|
|
868
1273
|
#loadBrowser() {
|
|
869
|
-
|
|
870
|
-
if (this.#options?.browser === void 0) browser = _puppeteer_browsers.Browser.CHROMIUM;
|
|
871
|
-
else browser = this.#options.browser;
|
|
872
|
-
this.#browser = browser;
|
|
1274
|
+
this.#browser = this.#options?.browser ?? DEFAULT_BROWSER;
|
|
873
1275
|
}
|
|
874
1276
|
getBrowser() {
|
|
875
1277
|
return this.#browser;
|
|
@@ -877,7 +1279,7 @@ let BrowserService = class BrowserService {
|
|
|
877
1279
|
#loadBrowserTag() {
|
|
878
1280
|
let versionTag;
|
|
879
1281
|
if (this.#options?.browserTag === void 0) {
|
|
880
|
-
if (this.#browser ===
|
|
1282
|
+
if (this.#browser === DEFAULT_BROWSER) versionTag = "latest";
|
|
881
1283
|
else versionTag = "stable";
|
|
882
1284
|
} else versionTag = this.#options.browserTag;
|
|
883
1285
|
this.#browserTag = versionTag;
|
|
@@ -904,21 +1306,24 @@ let BrowserService = class BrowserService {
|
|
|
904
1306
|
this.#useLockedBrowser = useLockedBrowser;
|
|
905
1307
|
}
|
|
906
1308
|
async hasBrowserInstalled(browser, buildId) {
|
|
907
|
-
|
|
908
|
-
|
|
1309
|
+
const { Browser: BrowserEnum, getInstalledBrowsers } = await loadPuppeteerBrowsers();
|
|
1310
|
+
const expected = toEnumMember(BrowserEnum, browser, "browser");
|
|
1311
|
+
return (await getInstalledBrowsers({ cacheDir: this.#cacheDir })).find((insBrowser) => {
|
|
1312
|
+
return insBrowser.browser === expected && insBrowser.buildId === buildId;
|
|
909
1313
|
}) !== void 0;
|
|
910
1314
|
}
|
|
911
1315
|
async getExecutablePath() {
|
|
912
|
-
const
|
|
1316
|
+
const { Browser: BrowserEnum, BrowserPlatform, detectBrowserPlatform, getInstalledBrowsers, resolveBuildId } = await loadPuppeteerBrowsers();
|
|
1317
|
+
const browser = toEnumMember(BrowserEnum, this.#browser, "browser");
|
|
913
1318
|
const versionTag = this.#browserTag;
|
|
914
|
-
const browserPlatform =
|
|
1319
|
+
const browserPlatform = detectBrowserPlatform() ?? BrowserPlatform.LINUX;
|
|
915
1320
|
let buildId = null;
|
|
916
1321
|
if (this.#useLockedBrowser) {
|
|
917
1322
|
buildId = this.getLockedBuildId(browser);
|
|
918
1323
|
_nestjs_common.Logger.log(`Using locked browser ${buildId}`, "NestJsPdf");
|
|
919
1324
|
}
|
|
920
|
-
buildId ??= await
|
|
921
|
-
const installedBrowser = (await
|
|
1325
|
+
buildId ??= await resolveBuildId(browser, browserPlatform, versionTag);
|
|
1326
|
+
const installedBrowser = (await getInstalledBrowsers({ cacheDir: this.#cacheDir })).find((insBrowser) => {
|
|
922
1327
|
return insBrowser.browser === browser && insBrowser.buildId === buildId;
|
|
923
1328
|
});
|
|
924
1329
|
if (installedBrowser === void 0) {
|
|
@@ -930,7 +1335,8 @@ let BrowserService = class BrowserService {
|
|
|
930
1335
|
}
|
|
931
1336
|
async #launchBrowser(args, headless, executablePathBin) {
|
|
932
1337
|
const executablePath = executablePathBin ?? await this.getExecutablePath();
|
|
933
|
-
const
|
|
1338
|
+
const { launch } = await loadPuppeteer();
|
|
1339
|
+
const browser = await launch({
|
|
934
1340
|
executablePath,
|
|
935
1341
|
headless,
|
|
936
1342
|
args,
|
|
@@ -966,8 +1372,7 @@ BrowserService = __decorate([
|
|
|
966
1372
|
__decorateParam(0, (0, _nestjs_common.Inject)("PDF_PARAMETERS")),
|
|
967
1373
|
__decorateMetadata("design:paramtypes", [Object])
|
|
968
1374
|
], BrowserService);
|
|
969
|
-
|
|
970
|
-
//#region src/puppeteer/libs/loadEngine.utils.ts
|
|
1375
|
+
// src/puppeteer/libs/loadEngine.utils.ts
|
|
971
1376
|
const requireEngine = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
972
1377
|
/**
|
|
973
1378
|
* Load an optional template engine on first use, so the library can be imported
|
|
@@ -984,8 +1389,7 @@ function loadEngine(packageName, engineName) {
|
|
|
984
1389
|
}
|
|
985
1390
|
return mod.__esModule && "default" in mod ? mod.default : mod;
|
|
986
1391
|
}
|
|
987
|
-
|
|
988
|
-
//#region src/puppeteer/engines/ejs/ejs.service.ts
|
|
1392
|
+
// src/puppeteer/engines/ejs/ejs.service.ts
|
|
989
1393
|
let EjsService = class EjsService {
|
|
990
1394
|
#ejs;
|
|
991
1395
|
get #engine() {
|
|
@@ -1015,8 +1419,7 @@ let EjsService = class EjsService {
|
|
|
1015
1419
|
}
|
|
1016
1420
|
};
|
|
1017
1421
|
EjsService = __decorate([(0, _nestjs_common.Injectable)()], EjsService);
|
|
1018
|
-
|
|
1019
|
-
//#region src/puppeteer/engines/eta/eta.service.ts
|
|
1422
|
+
// src/puppeteer/engines/eta/eta.service.ts
|
|
1020
1423
|
let EtaService = class EtaService {
|
|
1021
1424
|
#etaModule;
|
|
1022
1425
|
#eta;
|
|
@@ -1087,8 +1490,7 @@ let EtaService = class EtaService {
|
|
|
1087
1490
|
}
|
|
1088
1491
|
};
|
|
1089
1492
|
EtaService = __decorate([(0, _nestjs_common.Injectable)()], EtaService);
|
|
1090
|
-
|
|
1091
|
-
//#region src/puppeteer/engines/handlebars/handlebars.service.ts
|
|
1493
|
+
// src/puppeteer/engines/handlebars/handlebars.service.ts
|
|
1092
1494
|
let HandlebarsService = class HandlebarsService {
|
|
1093
1495
|
#handlebars;
|
|
1094
1496
|
#cachedOptions;
|
|
@@ -1143,8 +1545,7 @@ let HandlebarsService = class HandlebarsService {
|
|
|
1143
1545
|
}
|
|
1144
1546
|
};
|
|
1145
1547
|
HandlebarsService = __decorate([(0, _nestjs_common.Injectable)()], HandlebarsService);
|
|
1146
|
-
|
|
1147
|
-
//#region src/puppeteer/engines/liquid/liquid.service.ts
|
|
1548
|
+
// src/puppeteer/engines/liquid/liquid.service.ts
|
|
1148
1549
|
let LiquidService = class LiquidService {
|
|
1149
1550
|
#liquidModule;
|
|
1150
1551
|
#liquid;
|
|
@@ -1205,8 +1606,7 @@ let LiquidService = class LiquidService {
|
|
|
1205
1606
|
}
|
|
1206
1607
|
};
|
|
1207
1608
|
LiquidService = __decorate([(0, _nestjs_common.Injectable)()], LiquidService);
|
|
1208
|
-
|
|
1209
|
-
//#region src/puppeteer/engines/mjml/mjml.service.ts
|
|
1609
|
+
// src/puppeteer/engines/mjml/mjml.service.ts
|
|
1210
1610
|
let MjmlService = class MjmlService {
|
|
1211
1611
|
#mjml;
|
|
1212
1612
|
get #engine() {
|
|
@@ -1232,8 +1632,7 @@ let MjmlService = class MjmlService {
|
|
|
1232
1632
|
}
|
|
1233
1633
|
};
|
|
1234
1634
|
MjmlService = __decorate([(0, _nestjs_common.Injectable)()], MjmlService);
|
|
1235
|
-
|
|
1236
|
-
//#region src/puppeteer/engines/mustache/mustache.service.ts
|
|
1635
|
+
// src/puppeteer/engines/mustache/mustache.service.ts
|
|
1237
1636
|
let MustacheService = class MustacheService {
|
|
1238
1637
|
#mustache;
|
|
1239
1638
|
#templateCache = /* @__PURE__ */ new Map();
|
|
@@ -1296,8 +1695,7 @@ let MustacheService = class MustacheService {
|
|
|
1296
1695
|
}
|
|
1297
1696
|
};
|
|
1298
1697
|
MustacheService = __decorate([(0, _nestjs_common.Injectable)()], MustacheService);
|
|
1299
|
-
|
|
1300
|
-
//#region src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
1698
|
+
// src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
1301
1699
|
let NunjucksService = class NunjucksService {
|
|
1302
1700
|
#nunjucks;
|
|
1303
1701
|
get #engine() {
|
|
@@ -1349,8 +1747,7 @@ let NunjucksService = class NunjucksService {
|
|
|
1349
1747
|
}
|
|
1350
1748
|
};
|
|
1351
1749
|
NunjucksService = __decorate([(0, _nestjs_common.Injectable)()], NunjucksService);
|
|
1352
|
-
|
|
1353
|
-
//#region src/puppeteer/engines/pug/pug.service.ts
|
|
1750
|
+
// src/puppeteer/engines/pug/pug.service.ts
|
|
1354
1751
|
let PugService = class PugService {
|
|
1355
1752
|
#pug;
|
|
1356
1753
|
get #engine() {
|
|
@@ -1375,16 +1772,15 @@ let PugService = class PugService {
|
|
|
1375
1772
|
}
|
|
1376
1773
|
};
|
|
1377
1774
|
PugService = __decorate([(0, _nestjs_common.Injectable)()], PugService);
|
|
1378
|
-
|
|
1379
|
-
//#region src/puppeteer/libs/requireService.utils.ts
|
|
1775
|
+
// src/puppeteer/libs/requireService.utils.ts
|
|
1380
1776
|
function requireService(service, name) {
|
|
1381
1777
|
if (!service) throw new EngineNotAvailableException(name);
|
|
1382
1778
|
return service;
|
|
1383
1779
|
}
|
|
1384
|
-
|
|
1385
|
-
//#region src/puppeteer/puppeteer.service.ts
|
|
1780
|
+
// src/puppeteer/puppeteer.service.ts
|
|
1386
1781
|
let PuppeteerService = class PuppeteerService {
|
|
1387
|
-
#
|
|
1782
|
+
#renderer;
|
|
1783
|
+
#jobs;
|
|
1388
1784
|
#options;
|
|
1389
1785
|
#hbsService;
|
|
1390
1786
|
#mjmlService;
|
|
@@ -1394,8 +1790,9 @@ let PuppeteerService = class PuppeteerService {
|
|
|
1394
1790
|
#etaService;
|
|
1395
1791
|
#mustacheService;
|
|
1396
1792
|
#liquidService;
|
|
1397
|
-
constructor(
|
|
1398
|
-
this.#
|
|
1793
|
+
constructor(renderer, jobs, options, hbsService, mjmlService, pugService, ejsService, nunjucksService, etaService, mustacheService, liquidService) {
|
|
1794
|
+
this.#renderer = renderer;
|
|
1795
|
+
this.#jobs = jobs;
|
|
1399
1796
|
this.#options = options;
|
|
1400
1797
|
this.#hbsService = hbsService;
|
|
1401
1798
|
this.#mjmlService = mjmlService;
|
|
@@ -1414,87 +1811,19 @@ let PuppeteerService = class PuppeteerService {
|
|
|
1414
1811
|
const job = this.#limit(async () => {
|
|
1415
1812
|
signal?.throwIfAborted();
|
|
1416
1813
|
started = true;
|
|
1417
|
-
const
|
|
1418
|
-
|
|
1419
|
-
const headless = mergePuppeteerOptions.headless ?? true;
|
|
1420
|
-
const executablePath = mergePuppeteerOptions.executablePath || void 0;
|
|
1421
|
-
const args = mergePuppeteerOptions.extraPuppeteerArgs || [
|
|
1422
|
-
"--autoplay-policy=user-gesture-required",
|
|
1423
|
-
"--disable-background-networking",
|
|
1424
|
-
"--disable-background-timer-throttling",
|
|
1425
|
-
"--disable-backgrounding-occluded-windows",
|
|
1426
|
-
"--disable-breakpad",
|
|
1427
|
-
"--disable-client-side-phishing-detection",
|
|
1428
|
-
"--disable-component-update",
|
|
1429
|
-
"--disable-default-apps",
|
|
1430
|
-
"--disable-dev-shm-usage",
|
|
1431
|
-
"--disable-domain-reliability",
|
|
1432
|
-
"--disable-extensions",
|
|
1433
|
-
"--disable-features=AudioServiceOutOfProcess",
|
|
1434
|
-
"--disable-hang-monitor",
|
|
1435
|
-
"--disable-ipc-flooding-protection",
|
|
1436
|
-
"--disable-notifications",
|
|
1437
|
-
"--disable-offer-store-unmasked-wallet-cards",
|
|
1438
|
-
"--disable-print-preview",
|
|
1439
|
-
"--disable-prompt-on-repost",
|
|
1440
|
-
"--disable-renderer-backgrounding",
|
|
1441
|
-
"--disable-setuid-sandbox",
|
|
1442
|
-
"--disable-speech-api",
|
|
1443
|
-
"--disable-sync",
|
|
1444
|
-
"--hide-scrollbars",
|
|
1445
|
-
"--ignore-gpu-blacklist",
|
|
1446
|
-
"--metrics-recording-only",
|
|
1447
|
-
"--mute-audio",
|
|
1448
|
-
"--no-default-browser-check",
|
|
1449
|
-
"--no-first-run",
|
|
1450
|
-
"--no-pings",
|
|
1451
|
-
"--password-store=basic",
|
|
1452
|
-
"--use-gl=swiftshader",
|
|
1453
|
-
"--use-mock-keychain",
|
|
1454
|
-
"--disable-accelerated-2d-canvas",
|
|
1455
|
-
"--no-zygote",
|
|
1456
|
-
"--disable-gpu"
|
|
1457
|
-
];
|
|
1458
|
-
this.#browserService.markJobStarted();
|
|
1459
|
-
let context = null;
|
|
1460
|
-
let closing;
|
|
1461
|
-
const onAbort = () => {
|
|
1462
|
-
if (!context) return;
|
|
1463
|
-
closing = context.close();
|
|
1464
|
-
closing.catch(() => void 0);
|
|
1465
|
-
};
|
|
1466
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1814
|
+
const mergedOptions = mergePuppeteerParameters(this.#options, options);
|
|
1815
|
+
this.#jobs.markJobStarted();
|
|
1467
1816
|
try {
|
|
1468
|
-
|
|
1469
|
-
signal?.throwIfAborted();
|
|
1470
|
-
const page = await context.newPage();
|
|
1471
|
-
if (mergePuppeteerOptions.security) await installRequestGuard(context, page, mergePuppeteerOptions.security);
|
|
1472
|
-
const pdfOptions = mergePuppeteerOptions.pdfOptions ?? { format: "A4" };
|
|
1473
|
-
await page.setContent(html, { waitUntil: "domcontentloaded" });
|
|
1474
|
-
await page.emulateMediaType("screen");
|
|
1475
|
-
await page.waitForNetworkIdle({
|
|
1476
|
-
idleTime: 500,
|
|
1477
|
-
timeout: 3e4
|
|
1478
|
-
});
|
|
1479
|
-
/* v8 ignore next */
|
|
1480
|
-
await page.evaluate(() => document.fonts.ready);
|
|
1481
|
-
const pdf = await page.pdf(pdfOptions);
|
|
1817
|
+
const pdf = await this.#renderer.render(html, mergedOptions, signal);
|
|
1482
1818
|
signal?.throwIfAborted();
|
|
1483
|
-
return
|
|
1819
|
+
return mergedOptions.watermark ? await addWatermark(pdf, mergedOptions.watermark) : pdf;
|
|
1484
1820
|
} catch (e) {
|
|
1485
1821
|
if (signal?.aborted) throw signal.reason;
|
|
1486
1822
|
_nestjs_common.Logger.error(e);
|
|
1487
1823
|
if (e instanceof NestjsPdfException) throw e;
|
|
1488
1824
|
throw new PdfGenerationException(`PDF generation failed: ${String(e)}`, { cause: e });
|
|
1489
1825
|
} finally {
|
|
1490
|
-
|
|
1491
|
-
if (context) try {
|
|
1492
|
-
if (closing) await closing;
|
|
1493
|
-
else await context.close();
|
|
1494
|
-
} catch (error) {
|
|
1495
|
-
_nestjs_common.Logger.error(error);
|
|
1496
|
-
}
|
|
1497
|
-
await this.#browserService.markJobFinished();
|
|
1826
|
+
await this.#jobs.markJobFinished();
|
|
1498
1827
|
}
|
|
1499
1828
|
});
|
|
1500
1829
|
if (!signal) return job;
|
|
@@ -1578,8 +1907,9 @@ let PuppeteerService = class PuppeteerService {
|
|
|
1578
1907
|
};
|
|
1579
1908
|
PuppeteerService = __decorate([
|
|
1580
1909
|
(0, _nestjs_common.Injectable)(),
|
|
1581
|
-
__decorateParam(
|
|
1582
|
-
__decorateParam(
|
|
1910
|
+
__decorateParam(0, (0, _nestjs_common.Inject)(PDF_RENDERER)),
|
|
1911
|
+
__decorateParam(1, (0, _nestjs_common.Inject)(BrowserService)),
|
|
1912
|
+
__decorateParam(2, (0, _nestjs_common.Inject)(PDF_PARAMETERS)),
|
|
1583
1913
|
__decorateParam(3, (0, _nestjs_common.Optional)()),
|
|
1584
1914
|
__decorateParam(4, (0, _nestjs_common.Optional)()),
|
|
1585
1915
|
__decorateParam(5, (0, _nestjs_common.Optional)()),
|
|
@@ -1587,8 +1917,10 @@ PuppeteerService = __decorate([
|
|
|
1587
1917
|
__decorateParam(7, (0, _nestjs_common.Optional)()),
|
|
1588
1918
|
__decorateParam(8, (0, _nestjs_common.Optional)()),
|
|
1589
1919
|
__decorateParam(9, (0, _nestjs_common.Optional)()),
|
|
1920
|
+
__decorateParam(10, (0, _nestjs_common.Optional)()),
|
|
1590
1921
|
__decorateMetadata("design:paramtypes", [
|
|
1591
|
-
|
|
1922
|
+
Object,
|
|
1923
|
+
Object,
|
|
1592
1924
|
Object,
|
|
1593
1925
|
typeof HandlebarsService === "undefined" ? Object : HandlebarsService,
|
|
1594
1926
|
typeof MjmlService === "undefined" ? Object : MjmlService,
|
|
@@ -1600,8 +1932,7 @@ PuppeteerService = __decorate([
|
|
|
1600
1932
|
typeof LiquidService === "undefined" ? Object : LiquidService
|
|
1601
1933
|
])
|
|
1602
1934
|
], PuppeteerService);
|
|
1603
|
-
|
|
1604
|
-
//#region src/nestjs-pdf.service.ts
|
|
1935
|
+
// src/nestjs-pdf.service.ts
|
|
1605
1936
|
let NestjsPdfService = class NestjsPdfService {
|
|
1606
1937
|
#puppeteerService;
|
|
1607
1938
|
constructor(puppeteerService) {
|
|
@@ -1821,9 +2152,14 @@ let NestjsPdfService = class NestjsPdfService {
|
|
|
1821
2152
|
}
|
|
1822
2153
|
};
|
|
1823
2154
|
NestjsPdfService = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof PuppeteerService === "undefined" ? Object : PuppeteerService])], NestjsPdfService);
|
|
1824
|
-
|
|
1825
|
-
//#region src/puppeteer/puppeteer.module.ts
|
|
2155
|
+
// src/puppeteer/puppeteer.module.ts
|
|
1826
2156
|
var _PuppeteerModule;
|
|
2157
|
+
/** Builds the renderer of the configured provider, once the parameters are known. */
|
|
2158
|
+
const pdfRendererProvider = {
|
|
2159
|
+
provide: PDF_RENDERER,
|
|
2160
|
+
inject: [PDF_PARAMETERS, BrowserService],
|
|
2161
|
+
useFactory: createPdfRenderer
|
|
2162
|
+
};
|
|
1827
2163
|
let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
1828
2164
|
#browserService;
|
|
1829
2165
|
#pdfParams;
|
|
@@ -1832,7 +2168,12 @@ let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
|
1832
2168
|
this.#pdfParams = pdfParams;
|
|
1833
2169
|
}
|
|
1834
2170
|
async onModuleInit() {
|
|
1835
|
-
if (!this.#pdfParams
|
|
2171
|
+
if (!usesPuppeteer(this.#pdfParams)) return;
|
|
2172
|
+
await loadPuppeteer();
|
|
2173
|
+
if (!this.#pdfParams.executablePath) {
|
|
2174
|
+
await loadPuppeteerBrowsers();
|
|
2175
|
+
await this.#browserService.install(this.#pdfParams.useLockedBrowser ?? false);
|
|
2176
|
+
}
|
|
1836
2177
|
}
|
|
1837
2178
|
static forRoot(pdfParameters) {
|
|
1838
2179
|
return {
|
|
@@ -1876,6 +2217,7 @@ let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
|
1876
2217
|
pdfParamsProvider,
|
|
1877
2218
|
PuppeteerService,
|
|
1878
2219
|
BrowserService,
|
|
2220
|
+
pdfRendererProvider,
|
|
1879
2221
|
HandlebarsService,
|
|
1880
2222
|
MjmlService,
|
|
1881
2223
|
PugService,
|
|
@@ -1903,6 +2245,7 @@ PuppeteerModule = _PuppeteerModule = __decorate([
|
|
|
1903
2245
|
providers: [
|
|
1904
2246
|
PuppeteerService,
|
|
1905
2247
|
BrowserService,
|
|
2248
|
+
pdfRendererProvider,
|
|
1906
2249
|
MjmlService,
|
|
1907
2250
|
PugService,
|
|
1908
2251
|
EjsService,
|
|
@@ -1922,11 +2265,11 @@ PuppeteerModule = _PuppeteerModule = __decorate([
|
|
|
1922
2265
|
LiquidService
|
|
1923
2266
|
]
|
|
1924
2267
|
}),
|
|
2268
|
+
__decorateParam(0, (0, _nestjs_common.Inject)(BrowserService)),
|
|
1925
2269
|
__decorateParam(1, (0, _nestjs_common.Inject)(PDF_PARAMETERS)),
|
|
1926
|
-
__decorateMetadata("design:paramtypes", [
|
|
2270
|
+
__decorateMetadata("design:paramtypes", [Object, Object])
|
|
1927
2271
|
], PuppeteerModule);
|
|
1928
|
-
|
|
1929
|
-
//#region src/nestjs-pdf.module.ts
|
|
2272
|
+
// src/nestjs-pdf.module.ts
|
|
1930
2273
|
var _NestjsPdfModule;
|
|
1931
2274
|
let NestjsPdfModule = _NestjsPdfModule = class NestjsPdfModule {
|
|
1932
2275
|
static forRoot(options) {
|
|
@@ -1947,7 +2290,6 @@ let NestjsPdfModule = _NestjsPdfModule = class NestjsPdfModule {
|
|
|
1947
2290
|
}
|
|
1948
2291
|
};
|
|
1949
2292
|
NestjsPdfModule = _NestjsPdfModule = __decorate([(0, _nestjs_common.Module)({})], NestjsPdfModule);
|
|
1950
|
-
//#endregion
|
|
1951
2293
|
exports.BrowserInstallationException = BrowserInstallationException;
|
|
1952
2294
|
exports.BrowserUnavailableException = BrowserUnavailableException;
|
|
1953
2295
|
Object.defineProperty(exports, "EjsService", {
|
|
@@ -2026,6 +2368,7 @@ Object.defineProperty(exports, "PuppeteerService", {
|
|
|
2026
2368
|
return PuppeteerService;
|
|
2027
2369
|
}
|
|
2028
2370
|
});
|
|
2371
|
+
exports.RendererConfigurationException = RendererConfigurationException;
|
|
2029
2372
|
exports.SignatureDependencyException = SignatureDependencyException;
|
|
2030
2373
|
exports.SignaturePlacementException = SignaturePlacementException;
|
|
2031
2374
|
exports.TemplateConfigurationException = TemplateConfigurationException;
|