@shad0wz7/nestjs-pdf 3.2.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 +129 -30
- package/dist/index.cjs +723 -243
- package/dist/index.d.cts +320 -88
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +320 -88
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +702 -201
- package/dist/index.mjs.map +1 -1
- package/package.json +100 -50
package/dist/index.cjs
CHANGED
|
@@ -1,50 +1,14 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
//#region \0rolldown/runtime.js
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
-
key = keys[i];
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
-
get: ((k) => from[k]).bind(null, key),
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
20
|
-
value: mod,
|
|
21
|
-
enumerable: true
|
|
22
|
-
}) : target, mod));
|
|
23
|
-
//#endregion
|
|
24
2
|
let node_path = require("node:path");
|
|
25
3
|
let _nestjs_common = require("@nestjs/common");
|
|
26
4
|
let pdf_lib = require("pdf-lib");
|
|
27
5
|
let deepmerge_ts = require("deepmerge-ts");
|
|
28
|
-
let node_dns_promises = require("node:dns/promises");
|
|
29
6
|
let node_fs = require("node:fs");
|
|
7
|
+
let node_dns_promises = require("node:dns/promises");
|
|
30
8
|
let node_net = require("node:net");
|
|
31
9
|
let node_url = require("node:url");
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
let ejs = require("ejs");
|
|
35
|
-
ejs = __toESM(ejs, 1);
|
|
36
|
-
let eta = require("eta");
|
|
37
|
-
let handlebars = require("handlebars");
|
|
38
|
-
handlebars = __toESM(handlebars, 1);
|
|
39
|
-
let mjml = require("mjml");
|
|
40
|
-
mjml = __toESM(mjml, 1);
|
|
41
|
-
let mustache = require("mustache");
|
|
42
|
-
mustache = __toESM(mustache, 1);
|
|
43
|
-
let nunjucks = require("nunjucks");
|
|
44
|
-
nunjucks = __toESM(nunjucks, 1);
|
|
45
|
-
let pug = require("pug");
|
|
46
|
-
pug = __toESM(pug, 1);
|
|
47
|
-
//#region src/exceptions/nestjs-pdf.exception.ts
|
|
10
|
+
let node_module = require("node:module");
|
|
11
|
+
// src/exceptions/nestjs-pdf.exception.ts
|
|
48
12
|
let NestjsPdfErrorCode = /* @__PURE__ */ function(NestjsPdfErrorCode) {
|
|
49
13
|
NestjsPdfErrorCode["ENGINE_NOT_AVAILABLE"] = "ENGINE_NOT_AVAILABLE";
|
|
50
14
|
NestjsPdfErrorCode["TEMPLATE_CONFIGURATION_ERROR"] = "TEMPLATE_CONFIGURATION_ERROR";
|
|
@@ -55,6 +19,7 @@ let NestjsPdfErrorCode = /* @__PURE__ */ function(NestjsPdfErrorCode) {
|
|
|
55
19
|
NestjsPdfErrorCode["SIGNATURE_DEPENDENCY_ERROR"] = "SIGNATURE_DEPENDENCY_ERROR";
|
|
56
20
|
NestjsPdfErrorCode["SIGNATURE_PLACEMENT_ERROR"] = "SIGNATURE_PLACEMENT_ERROR";
|
|
57
21
|
NestjsPdfErrorCode["WATERMARK_ERROR"] = "WATERMARK_ERROR";
|
|
22
|
+
NestjsPdfErrorCode["RENDERER_CONFIGURATION_ERROR"] = "RENDERER_CONFIGURATION_ERROR";
|
|
58
23
|
return NestjsPdfErrorCode;
|
|
59
24
|
}({});
|
|
60
25
|
var NestjsPdfException = class extends Error {
|
|
@@ -63,46 +28,43 @@ var NestjsPdfException = class extends Error {
|
|
|
63
28
|
this.name = this.constructor.name;
|
|
64
29
|
}
|
|
65
30
|
};
|
|
66
|
-
|
|
67
|
-
//#region src/exceptions/browser-installation.exception.ts
|
|
31
|
+
// src/exceptions/browser-installation.exception.ts
|
|
68
32
|
var BrowserInstallationException = class extends NestjsPdfException {
|
|
69
33
|
code = "BROWSER_INSTALLATION_ERROR";
|
|
70
34
|
};
|
|
71
|
-
|
|
72
|
-
//#region src/exceptions/browser-unavailable.exception.ts
|
|
35
|
+
// src/exceptions/browser-unavailable.exception.ts
|
|
73
36
|
var BrowserUnavailableException = class extends NestjsPdfException {
|
|
74
37
|
code = "BROWSER_UNAVAILABLE";
|
|
75
38
|
};
|
|
76
|
-
|
|
77
|
-
//#region src/exceptions/engine-not-available.exception.ts
|
|
39
|
+
// src/exceptions/engine-not-available.exception.ts
|
|
78
40
|
var EngineNotAvailableException = class extends NestjsPdfException {
|
|
79
41
|
code = "ENGINE_NOT_AVAILABLE";
|
|
80
|
-
constructor(engineName) {
|
|
81
|
-
super(`${engineName} service is not available. If the problem persists, open an issue in the repo
|
|
42
|
+
constructor(engineName, packageName, options) {
|
|
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);
|
|
82
44
|
}
|
|
83
45
|
};
|
|
84
|
-
|
|
85
|
-
//#region src/exceptions/pdf-generation.exception.ts
|
|
46
|
+
// src/exceptions/pdf-generation.exception.ts
|
|
86
47
|
var PdfGenerationException = class extends NestjsPdfException {
|
|
87
48
|
code = "PDF_GENERATION_ERROR";
|
|
88
49
|
};
|
|
89
|
-
|
|
90
|
-
|
|
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
|
|
91
56
|
var SignatureDependencyException = class extends NestjsPdfException {
|
|
92
57
|
code = "SIGNATURE_DEPENDENCY_ERROR";
|
|
93
58
|
};
|
|
94
|
-
|
|
95
|
-
//#region src/exceptions/signature-placement.exception.ts
|
|
59
|
+
// src/exceptions/signature-placement.exception.ts
|
|
96
60
|
var SignaturePlacementException = class extends NestjsPdfException {
|
|
97
61
|
code = "SIGNATURE_PLACEMENT_ERROR";
|
|
98
62
|
};
|
|
99
|
-
|
|
100
|
-
//#region src/exceptions/template-configuration.exception.ts
|
|
63
|
+
// src/exceptions/template-configuration.exception.ts
|
|
101
64
|
var TemplateConfigurationException = class extends NestjsPdfException {
|
|
102
65
|
code = "TEMPLATE_CONFIGURATION_ERROR";
|
|
103
66
|
};
|
|
104
|
-
|
|
105
|
-
//#region src/exceptions/template-render.exception.ts
|
|
67
|
+
// src/exceptions/template-render.exception.ts
|
|
106
68
|
var TemplateRenderException = class extends NestjsPdfException {
|
|
107
69
|
engine;
|
|
108
70
|
code = "TEMPLATE_RENDER_ERROR";
|
|
@@ -111,13 +73,11 @@ var TemplateRenderException = class extends NestjsPdfException {
|
|
|
111
73
|
this.engine = engine;
|
|
112
74
|
}
|
|
113
75
|
};
|
|
114
|
-
|
|
115
|
-
//#region src/exceptions/watermark.exception.ts
|
|
76
|
+
// src/exceptions/watermark.exception.ts
|
|
116
77
|
var WatermarkException = class extends NestjsPdfException {
|
|
117
78
|
code = "WATERMARK_ERROR";
|
|
118
79
|
};
|
|
119
|
-
|
|
120
|
-
//#region src/helpers/getRelativePath.helper.ts
|
|
80
|
+
// src/helpers/getRelativePath.helper.ts
|
|
121
81
|
/**
|
|
122
82
|
* Get the relative path to a value from the module directory.
|
|
123
83
|
* @param moduleDir the path of the module, typically __dirname
|
|
@@ -131,8 +91,7 @@ function getRelativePathToValue(moduleDir, relativeToModule) {
|
|
|
131
91
|
const fullTemplatePath = (0, node_path.resolve)(moduleDir, relativeToModule);
|
|
132
92
|
return (0, node_path.relative)(process.cwd(), fullTemplatePath);
|
|
133
93
|
}
|
|
134
|
-
|
|
135
|
-
//#region src/helpers/signature.helper.ts
|
|
94
|
+
// src/helpers/signature.helper.ts
|
|
136
95
|
let pdfjsPromise;
|
|
137
96
|
async function loadPdfjs() {
|
|
138
97
|
if (!pdfjsPromise) try {
|
|
@@ -275,8 +234,7 @@ async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor",
|
|
|
275
234
|
}
|
|
276
235
|
return await pdfDoc.save();
|
|
277
236
|
}
|
|
278
|
-
|
|
279
|
-
//#region src/helpers/watermark.helper.ts
|
|
237
|
+
// src/helpers/watermark.helper.ts
|
|
280
238
|
const DEFAULT_OPACITY = .15;
|
|
281
239
|
const DEFAULT_ROTATION = 45;
|
|
282
240
|
const DEFAULT_FONT_SIZE = 60;
|
|
@@ -419,8 +377,7 @@ async function addWatermark(pdf, options) {
|
|
|
419
377
|
throw new WatermarkException(`Failed to add watermark: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
420
378
|
}
|
|
421
379
|
}
|
|
422
|
-
|
|
423
|
-
//#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
|
|
424
381
|
var Node = class {
|
|
425
382
|
value;
|
|
426
383
|
next;
|
|
@@ -477,8 +434,7 @@ var Queue = class {
|
|
|
477
434
|
while (this.#head) yield this.dequeue();
|
|
478
435
|
}
|
|
479
436
|
};
|
|
480
|
-
|
|
481
|
-
//#region node_modules/.pnpm/p-limit@7.3.2/node_modules/p-limit/index.js
|
|
437
|
+
// node_modules/.pnpm/p-limit@7.3.3/node_modules/p-limit/index.js
|
|
482
438
|
function pLimit(concurrency) {
|
|
483
439
|
let rejectOnClear = false;
|
|
484
440
|
if (typeof concurrency === "object") ({concurrency, rejectOnClear = false} = concurrency);
|
|
@@ -537,7 +493,17 @@ function pLimit(concurrency) {
|
|
|
537
493
|
}
|
|
538
494
|
},
|
|
539
495
|
map: { async value(iterable, function_) {
|
|
540
|
-
const promises =
|
|
496
|
+
const promises = [];
|
|
497
|
+
try {
|
|
498
|
+
Array.from(iterable, (value, index) => {
|
|
499
|
+
const promise = generator(function_, value, index);
|
|
500
|
+
promises.push(promise);
|
|
501
|
+
return promise;
|
|
502
|
+
});
|
|
503
|
+
} catch (error) {
|
|
504
|
+
for (const promise of promises) promise.catch(() => {});
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
541
507
|
return Promise.all(promises);
|
|
542
508
|
} }
|
|
543
509
|
});
|
|
@@ -546,14 +512,296 @@ function pLimit(concurrency) {
|
|
|
546
512
|
function validateConcurrency(concurrency) {
|
|
547
513
|
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
|
|
548
514
|
}
|
|
549
|
-
|
|
550
|
-
//#region src/helpers/deepMergePdfparams.ts
|
|
515
|
+
// src/helpers/deepMergePdfparams.ts
|
|
551
516
|
function mergePuppeteerParameters(defaults, overrides) {
|
|
552
517
|
if (!overrides) return { ...defaults };
|
|
553
518
|
return (0, deepmerge_ts.deepmerge)(defaults, overrides);
|
|
554
519
|
}
|
|
555
|
-
|
|
556
|
-
|
|
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
|
|
557
805
|
const blockedRanges = new node_net.BlockList();
|
|
558
806
|
for (const [address, prefix] of [
|
|
559
807
|
["0.0.0.0", 8],
|
|
@@ -681,8 +929,9 @@ function describe(rawUrl) {
|
|
|
681
929
|
* and closes the pop-ups a script could open to escape the filter.
|
|
682
930
|
*/
|
|
683
931
|
async function installRequestGuard(context, page, options) {
|
|
932
|
+
const { TargetType } = await loadPuppeteer();
|
|
684
933
|
context.on("targetcreated", (target) => {
|
|
685
|
-
if (target.type() ===
|
|
934
|
+
if (target.type() === TargetType.PAGE && target.opener()) target.page().then((popup) => popup?.close()).catch(() => void 0);
|
|
686
935
|
});
|
|
687
936
|
if (options.javascriptEnabled === false) await page.setJavaScriptEnabled(false);
|
|
688
937
|
await page.setRequestInterception(true);
|
|
@@ -700,31 +949,162 @@ async function installRequestGuard(context, page, options) {
|
|
|
700
949
|
})().catch(() => void 0);
|
|
701
950
|
});
|
|
702
951
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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
|
|
708
1090
|
function __decorateMetadata(k, v) {
|
|
709
1091
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
710
1092
|
}
|
|
711
|
-
|
|
712
|
-
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorateParam.js
|
|
1093
|
+
// \0@oxc-project+runtime@0.156.0/helpers/esm/decorateParam.js
|
|
713
1094
|
function __decorateParam(paramIndex, decorator) {
|
|
714
1095
|
return function(target, key) {
|
|
715
1096
|
decorator(target, key, paramIndex);
|
|
716
1097
|
};
|
|
717
1098
|
}
|
|
718
|
-
|
|
719
|
-
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorate.js
|
|
1099
|
+
// \0@oxc-project+runtime@0.156.0/helpers/esm/decorate.js
|
|
720
1100
|
function __decorate(decorators, target, key, desc) {
|
|
721
1101
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
722
1102
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
723
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;
|
|
724
1104
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
725
1105
|
}
|
|
726
|
-
|
|
727
|
-
|
|
1106
|
+
// src/puppeteer/browser/browser.service.ts
|
|
1107
|
+
const DEFAULT_BROWSER = "chromium";
|
|
728
1108
|
async function sleep(ms) {
|
|
729
1109
|
await new Promise((r) => setTimeout(r, ms));
|
|
730
1110
|
}
|
|
@@ -776,7 +1156,7 @@ let BrowserService = class BrowserService {
|
|
|
776
1156
|
} catch (error) {
|
|
777
1157
|
_nestjs_common.Logger.warn(`Failed to close browser on module destroy: ${error instanceof Error ? error.message : String(error)}`);
|
|
778
1158
|
}
|
|
779
|
-
if (this.#options
|
|
1159
|
+
if (this.#options !== void 0 && usesPuppeteer(this.#options) && this.#options.cleanupBrowserCacheOnExit !== false) await this.#cleanupCacheBestEffort();
|
|
780
1160
|
}
|
|
781
1161
|
/** Wait until no PDF job is in flight, or until the timeout elapses. */
|
|
782
1162
|
async #waitForIdle(timeoutMs) {
|
|
@@ -858,11 +1238,12 @@ let BrowserService = class BrowserService {
|
|
|
858
1238
|
}
|
|
859
1239
|
}
|
|
860
1240
|
async #doInstall(lock) {
|
|
861
|
-
const
|
|
1241
|
+
const { Browser: BrowserEnum, BrowserPlatform, canDownload, detectBrowserPlatform, install, resolveBuildId } = await loadPuppeteerBrowsers();
|
|
1242
|
+
const browser = toEnumMember(BrowserEnum, this.#browser, "browser");
|
|
862
1243
|
const versionTag = this.#browserTag;
|
|
863
|
-
const browserPlatform =
|
|
1244
|
+
const browserPlatform = detectBrowserPlatform() ?? BrowserPlatform.LINUX;
|
|
864
1245
|
let buildId;
|
|
865
|
-
if (this.#buildId === void 0) buildId = await
|
|
1246
|
+
if (this.#buildId === void 0) buildId = await resolveBuildId(browser, browserPlatform, versionTag);
|
|
866
1247
|
else buildId = this.#buildId;
|
|
867
1248
|
_nestjs_common.Logger.log(`Browser ${browser} ${versionTag} build id: ${buildId}`, "NestJsPdf");
|
|
868
1249
|
if (await this.hasBrowserInstalled(browser, buildId)) {
|
|
@@ -877,9 +1258,9 @@ let BrowserService = class BrowserService {
|
|
|
877
1258
|
buildId,
|
|
878
1259
|
baseUrl: this.#options?.browserInstallBaseUrl ?? void 0
|
|
879
1260
|
};
|
|
880
|
-
if (await
|
|
1261
|
+
if (await canDownload(installOption)) {
|
|
881
1262
|
_nestjs_common.Logger.log(`Installing ${installOption.browser} ${installOption.buildId}`, "NestJsPdf");
|
|
882
|
-
const installedBrowser = await
|
|
1263
|
+
const installedBrowser = await install(installOption);
|
|
883
1264
|
if (await this.hasBrowserInstalled(browser, buildId)) {
|
|
884
1265
|
_nestjs_common.Logger.log("Browser installed successfully", "NestJsPdf");
|
|
885
1266
|
if (lock) this.#writeLockFile(browser, buildId);
|
|
@@ -890,10 +1271,7 @@ let BrowserService = class BrowserService {
|
|
|
890
1271
|
return null;
|
|
891
1272
|
}
|
|
892
1273
|
#loadBrowser() {
|
|
893
|
-
|
|
894
|
-
if (this.#options?.browser === void 0) browser = _puppeteer_browsers.Browser.CHROMIUM;
|
|
895
|
-
else browser = this.#options.browser;
|
|
896
|
-
this.#browser = browser;
|
|
1274
|
+
this.#browser = this.#options?.browser ?? DEFAULT_BROWSER;
|
|
897
1275
|
}
|
|
898
1276
|
getBrowser() {
|
|
899
1277
|
return this.#browser;
|
|
@@ -901,7 +1279,7 @@ let BrowserService = class BrowserService {
|
|
|
901
1279
|
#loadBrowserTag() {
|
|
902
1280
|
let versionTag;
|
|
903
1281
|
if (this.#options?.browserTag === void 0) {
|
|
904
|
-
if (this.#browser ===
|
|
1282
|
+
if (this.#browser === DEFAULT_BROWSER) versionTag = "latest";
|
|
905
1283
|
else versionTag = "stable";
|
|
906
1284
|
} else versionTag = this.#options.browserTag;
|
|
907
1285
|
this.#browserTag = versionTag;
|
|
@@ -928,21 +1306,24 @@ let BrowserService = class BrowserService {
|
|
|
928
1306
|
this.#useLockedBrowser = useLockedBrowser;
|
|
929
1307
|
}
|
|
930
1308
|
async hasBrowserInstalled(browser, buildId) {
|
|
931
|
-
|
|
932
|
-
|
|
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;
|
|
933
1313
|
}) !== void 0;
|
|
934
1314
|
}
|
|
935
1315
|
async getExecutablePath() {
|
|
936
|
-
const
|
|
1316
|
+
const { Browser: BrowserEnum, BrowserPlatform, detectBrowserPlatform, getInstalledBrowsers, resolveBuildId } = await loadPuppeteerBrowsers();
|
|
1317
|
+
const browser = toEnumMember(BrowserEnum, this.#browser, "browser");
|
|
937
1318
|
const versionTag = this.#browserTag;
|
|
938
|
-
const browserPlatform =
|
|
1319
|
+
const browserPlatform = detectBrowserPlatform() ?? BrowserPlatform.LINUX;
|
|
939
1320
|
let buildId = null;
|
|
940
1321
|
if (this.#useLockedBrowser) {
|
|
941
1322
|
buildId = this.getLockedBuildId(browser);
|
|
942
1323
|
_nestjs_common.Logger.log(`Using locked browser ${buildId}`, "NestJsPdf");
|
|
943
1324
|
}
|
|
944
|
-
buildId ??= await
|
|
945
|
-
const installedBrowser = (await
|
|
1325
|
+
buildId ??= await resolveBuildId(browser, browserPlatform, versionTag);
|
|
1326
|
+
const installedBrowser = (await getInstalledBrowsers({ cacheDir: this.#cacheDir })).find((insBrowser) => {
|
|
946
1327
|
return insBrowser.browser === browser && insBrowser.buildId === buildId;
|
|
947
1328
|
});
|
|
948
1329
|
if (installedBrowser === void 0) {
|
|
@@ -954,7 +1335,8 @@ let BrowserService = class BrowserService {
|
|
|
954
1335
|
}
|
|
955
1336
|
async #launchBrowser(args, headless, executablePathBin) {
|
|
956
1337
|
const executablePath = executablePathBin ?? await this.getExecutablePath();
|
|
957
|
-
const
|
|
1338
|
+
const { launch } = await loadPuppeteer();
|
|
1339
|
+
const browser = await launch({
|
|
958
1340
|
executablePath,
|
|
959
1341
|
headless,
|
|
960
1342
|
args,
|
|
@@ -990,12 +1372,33 @@ BrowserService = __decorate([
|
|
|
990
1372
|
__decorateParam(0, (0, _nestjs_common.Inject)("PDF_PARAMETERS")),
|
|
991
1373
|
__decorateMetadata("design:paramtypes", [Object])
|
|
992
1374
|
], BrowserService);
|
|
993
|
-
|
|
994
|
-
|
|
1375
|
+
// src/puppeteer/libs/loadEngine.utils.ts
|
|
1376
|
+
const requireEngine = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
1377
|
+
/**
|
|
1378
|
+
* Load an optional template engine on first use, so the library can be imported
|
|
1379
|
+
* without every engine installed. `require` (not `import()`) is used on purpose:
|
|
1380
|
+
* most engines expose a synchronous render API.
|
|
1381
|
+
*/
|
|
1382
|
+
function loadEngine(packageName, engineName) {
|
|
1383
|
+
let mod;
|
|
1384
|
+
try {
|
|
1385
|
+
mod = requireEngine(packageName);
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
if (error.code === "MODULE_NOT_FOUND") throw new EngineNotAvailableException(engineName, packageName, { cause: error });
|
|
1388
|
+
throw error;
|
|
1389
|
+
}
|
|
1390
|
+
return mod.__esModule && "default" in mod ? mod.default : mod;
|
|
1391
|
+
}
|
|
1392
|
+
// src/puppeteer/engines/ejs/ejs.service.ts
|
|
995
1393
|
let EjsService = class EjsService {
|
|
1394
|
+
#ejs;
|
|
1395
|
+
get #engine() {
|
|
1396
|
+
return this.#ejs ??= loadEngine("ejs", "EJS");
|
|
1397
|
+
}
|
|
996
1398
|
async render(template, data = {}, options) {
|
|
1399
|
+
const engine = this.#engine;
|
|
997
1400
|
try {
|
|
998
|
-
return await
|
|
1401
|
+
return await engine.render(template, data, {
|
|
999
1402
|
async: true,
|
|
1000
1403
|
...options
|
|
1001
1404
|
});
|
|
@@ -1004,8 +1407,9 @@ let EjsService = class EjsService {
|
|
|
1004
1407
|
}
|
|
1005
1408
|
}
|
|
1006
1409
|
async renderFile(filePath, data = {}, options) {
|
|
1410
|
+
const engine = this.#engine;
|
|
1007
1411
|
try {
|
|
1008
|
-
return await
|
|
1412
|
+
return await engine.renderFile(filePath, data, {
|
|
1009
1413
|
async: true,
|
|
1010
1414
|
...options
|
|
1011
1415
|
});
|
|
@@ -1015,18 +1419,14 @@ 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 {
|
|
1424
|
+
#etaModule;
|
|
1021
1425
|
#eta;
|
|
1022
1426
|
#templateCache = /* @__PURE__ */ new Map();
|
|
1023
1427
|
#maxCacheSize = 100;
|
|
1024
|
-
|
|
1025
|
-
this.#
|
|
1026
|
-
cache: true,
|
|
1027
|
-
autoEscape: true,
|
|
1028
|
-
useWith: true
|
|
1029
|
-
});
|
|
1428
|
+
get #engine() {
|
|
1429
|
+
return this.#etaModule ??= loadEngine("eta", "Eta");
|
|
1030
1430
|
}
|
|
1031
1431
|
/**
|
|
1032
1432
|
* Render an Eta template from a string
|
|
@@ -1036,14 +1436,19 @@ let EtaService = class EtaService {
|
|
|
1036
1436
|
* @returns The rendered HTML string
|
|
1037
1437
|
*/
|
|
1038
1438
|
render(template, data = {}, options) {
|
|
1439
|
+
const { Eta } = this.#engine;
|
|
1039
1440
|
try {
|
|
1040
|
-
return (options && Object.keys(options).length > 0 ? new
|
|
1441
|
+
return (options && Object.keys(options).length > 0 ? new Eta({
|
|
1041
1442
|
cache: true,
|
|
1042
1443
|
autoEscape: true,
|
|
1043
1444
|
useWith: true,
|
|
1044
1445
|
...options,
|
|
1045
1446
|
varName: options.varName ?? "it"
|
|
1046
|
-
}) : this.#eta
|
|
1447
|
+
}) : this.#eta ??= new Eta({
|
|
1448
|
+
cache: true,
|
|
1449
|
+
autoEscape: true,
|
|
1450
|
+
useWith: true
|
|
1451
|
+
})).renderString(template, data);
|
|
1047
1452
|
} catch (error) {
|
|
1048
1453
|
throw new TemplateRenderException("Eta", `Eta rendering failed: ${String(error)}`, { cause: error });
|
|
1049
1454
|
}
|
|
@@ -1066,6 +1471,7 @@ let EtaService = class EtaService {
|
|
|
1066
1471
|
}
|
|
1067
1472
|
return this.render(template, data, options);
|
|
1068
1473
|
} catch (error) {
|
|
1474
|
+
if (error instanceof EngineNotAvailableException) throw error;
|
|
1069
1475
|
throw new TemplateRenderException("Eta", `Eta file rendering failed for ${filePath}: ${String(error)}`, { cause: error });
|
|
1070
1476
|
}
|
|
1071
1477
|
}
|
|
@@ -1083,12 +1489,15 @@ let EtaService = class EtaService {
|
|
|
1083
1489
|
return this.#templateCache.size;
|
|
1084
1490
|
}
|
|
1085
1491
|
};
|
|
1086
|
-
EtaService = __decorate([(0, _nestjs_common.Injectable)()
|
|
1087
|
-
|
|
1088
|
-
//#region src/puppeteer/engines/handlebars/handlebars.service.ts
|
|
1492
|
+
EtaService = __decorate([(0, _nestjs_common.Injectable)()], EtaService);
|
|
1493
|
+
// src/puppeteer/engines/handlebars/handlebars.service.ts
|
|
1089
1494
|
let HandlebarsService = class HandlebarsService {
|
|
1495
|
+
#handlebars;
|
|
1090
1496
|
#cachedOptions;
|
|
1091
1497
|
#cachedEnv;
|
|
1498
|
+
get #engine() {
|
|
1499
|
+
return this.#handlebars ??= loadEngine("handlebars", "Handlebars");
|
|
1500
|
+
}
|
|
1092
1501
|
render(template, parameters = {}, options = {}) {
|
|
1093
1502
|
try {
|
|
1094
1503
|
return this.#getEnv(options).compile(template, options.compileOptions)(parameters, options.templateOptions);
|
|
@@ -1117,7 +1526,7 @@ let HandlebarsService = class HandlebarsService {
|
|
|
1117
1526
|
*/
|
|
1118
1527
|
#getEnv(options) {
|
|
1119
1528
|
if (this.#cachedEnv && this.#cachedOptions === options) return this.#cachedEnv;
|
|
1120
|
-
const env =
|
|
1529
|
+
const env = this.#engine.create();
|
|
1121
1530
|
for (const helper of options.helpers ?? []) env.registerHelper(helper.name, helper.fn);
|
|
1122
1531
|
this.#registerPartials(env, options.partialDirectory);
|
|
1123
1532
|
this.#cachedOptions = options;
|
|
@@ -1136,12 +1545,77 @@ let HandlebarsService = class HandlebarsService {
|
|
|
1136
1545
|
}
|
|
1137
1546
|
};
|
|
1138
1547
|
HandlebarsService = __decorate([(0, _nestjs_common.Injectable)()], HandlebarsService);
|
|
1139
|
-
|
|
1140
|
-
|
|
1548
|
+
// src/puppeteer/engines/liquid/liquid.service.ts
|
|
1549
|
+
let LiquidService = class LiquidService {
|
|
1550
|
+
#liquidModule;
|
|
1551
|
+
#liquid;
|
|
1552
|
+
#templateCache = /* @__PURE__ */ new Map();
|
|
1553
|
+
#maxCacheSize = 100;
|
|
1554
|
+
get #engine() {
|
|
1555
|
+
return this.#liquidModule ??= loadEngine("liquidjs", "Liquid");
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Render a Liquid template from a string
|
|
1559
|
+
* @param template The template string to render
|
|
1560
|
+
* @param data The data object to use for rendering
|
|
1561
|
+
* @param options Optional Liquid engine options
|
|
1562
|
+
* @returns The rendered HTML string
|
|
1563
|
+
*/
|
|
1564
|
+
render(template, data = {}, options) {
|
|
1565
|
+
const { Liquid } = this.#engine;
|
|
1566
|
+
try {
|
|
1567
|
+
return (options && Object.keys(options).length > 0 ? new Liquid(options) : this.#liquid ??= new Liquid()).parseAndRenderSync(template, data);
|
|
1568
|
+
} catch (error) {
|
|
1569
|
+
throw new TemplateRenderException("Liquid", `Liquid rendering failed: ${String(error)}`, { cause: error });
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* Render a Liquid template from a file
|
|
1574
|
+
* @param filePath The path to the template file
|
|
1575
|
+
* @param data The data object to use for rendering
|
|
1576
|
+
* @param options Optional Liquid engine options
|
|
1577
|
+
* @returns The rendered HTML string
|
|
1578
|
+
*/
|
|
1579
|
+
renderFile(filePath, data = {}, options) {
|
|
1580
|
+
try {
|
|
1581
|
+
const resolvedPath = (0, node_path.resolve)(filePath);
|
|
1582
|
+
const useCache = options?.cache !== false;
|
|
1583
|
+
let template = useCache ? this.#templateCache.get(resolvedPath) : void 0;
|
|
1584
|
+
if (!template) {
|
|
1585
|
+
template = (0, node_fs.readFileSync)(resolvedPath, "utf-8");
|
|
1586
|
+
if (useCache && this.#templateCache.size < this.#maxCacheSize) this.#templateCache.set(resolvedPath, template);
|
|
1587
|
+
}
|
|
1588
|
+
return this.render(template, data, options);
|
|
1589
|
+
} catch (error) {
|
|
1590
|
+
if (error instanceof EngineNotAvailableException) throw error;
|
|
1591
|
+
throw new TemplateRenderException("Liquid", `Liquid file rendering failed for ${filePath}: ${String(error)}`, { cause: error });
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Clear the template cache
|
|
1596
|
+
*/
|
|
1597
|
+
clearCache() {
|
|
1598
|
+
this.#templateCache.clear();
|
|
1599
|
+
}
|
|
1600
|
+
/**
|
|
1601
|
+
* Get the current cache size
|
|
1602
|
+
* @returns The number of cached templates
|
|
1603
|
+
*/
|
|
1604
|
+
getCacheSize() {
|
|
1605
|
+
return this.#templateCache.size;
|
|
1606
|
+
}
|
|
1607
|
+
};
|
|
1608
|
+
LiquidService = __decorate([(0, _nestjs_common.Injectable)()], LiquidService);
|
|
1609
|
+
// src/puppeteer/engines/mjml/mjml.service.ts
|
|
1141
1610
|
let MjmlService = class MjmlService {
|
|
1611
|
+
#mjml;
|
|
1612
|
+
get #engine() {
|
|
1613
|
+
return this.#mjml ??= loadEngine("mjml", "MJML");
|
|
1614
|
+
}
|
|
1142
1615
|
async render(template, options) {
|
|
1616
|
+
const engine = this.#engine;
|
|
1143
1617
|
try {
|
|
1144
|
-
const { html } = await (
|
|
1618
|
+
const { html } = await engine(template, options);
|
|
1145
1619
|
return html;
|
|
1146
1620
|
} catch (error) {
|
|
1147
1621
|
throw new TemplateRenderException("MJML", `MJML rendering failed: ${String(error)}`, { cause: error });
|
|
@@ -1158,11 +1632,14 @@ let MjmlService = class MjmlService {
|
|
|
1158
1632
|
}
|
|
1159
1633
|
};
|
|
1160
1634
|
MjmlService = __decorate([(0, _nestjs_common.Injectable)()], MjmlService);
|
|
1161
|
-
|
|
1162
|
-
//#region src/puppeteer/engines/mustache/mustache.service.ts
|
|
1635
|
+
// src/puppeteer/engines/mustache/mustache.service.ts
|
|
1163
1636
|
let MustacheService = class MustacheService {
|
|
1637
|
+
#mustache;
|
|
1164
1638
|
#templateCache = /* @__PURE__ */ new Map();
|
|
1165
1639
|
#maxCacheSize = 100;
|
|
1640
|
+
get #engine() {
|
|
1641
|
+
return this.#mustache ??= loadEngine("mustache", "Mustache");
|
|
1642
|
+
}
|
|
1166
1643
|
/**
|
|
1167
1644
|
* Render a Mustache template from a string
|
|
1168
1645
|
* @param template The template string to render
|
|
@@ -1171,9 +1648,10 @@ let MustacheService = class MustacheService {
|
|
|
1171
1648
|
* @returns The rendered HTML string
|
|
1172
1649
|
*/
|
|
1173
1650
|
render(template, data = {}, options) {
|
|
1651
|
+
const engine = this.#engine;
|
|
1174
1652
|
try {
|
|
1175
1653
|
const tags = options?.tags ?? ["{{", "}}"];
|
|
1176
|
-
return
|
|
1654
|
+
return engine.render(template, data, void 0, {
|
|
1177
1655
|
tags,
|
|
1178
1656
|
escape: options?.escape
|
|
1179
1657
|
});
|
|
@@ -1198,6 +1676,7 @@ let MustacheService = class MustacheService {
|
|
|
1198
1676
|
}
|
|
1199
1677
|
return this.render(template, data, options);
|
|
1200
1678
|
} catch (error) {
|
|
1679
|
+
if (error instanceof EngineNotAvailableException) throw error;
|
|
1201
1680
|
throw new TemplateRenderException("Mustache", `Mustache file rendering failed for ${filePath}: ${String(error)}`, { cause: error });
|
|
1202
1681
|
}
|
|
1203
1682
|
}
|
|
@@ -1216,17 +1695,22 @@ let MustacheService = class MustacheService {
|
|
|
1216
1695
|
}
|
|
1217
1696
|
};
|
|
1218
1697
|
MustacheService = __decorate([(0, _nestjs_common.Injectable)()], MustacheService);
|
|
1219
|
-
|
|
1220
|
-
//#region src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
1698
|
+
// src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
1221
1699
|
let NunjucksService = class NunjucksService {
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1700
|
+
#nunjucks;
|
|
1701
|
+
get #engine() {
|
|
1702
|
+
if (!this.#nunjucks) {
|
|
1703
|
+
this.#nunjucks = loadEngine("nunjucks", "Nunjucks");
|
|
1704
|
+
this.#nunjucks.configure({
|
|
1705
|
+
noCache: true,
|
|
1706
|
+
trimBlocks: true,
|
|
1707
|
+
lstripBlocks: true
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
return this.#nunjucks;
|
|
1228
1711
|
}
|
|
1229
1712
|
render(template, data = {}, options) {
|
|
1713
|
+
const nunjucks = this.#engine;
|
|
1230
1714
|
try {
|
|
1231
1715
|
if (options) {
|
|
1232
1716
|
const configOptions = {
|
|
@@ -1236,14 +1720,15 @@ let NunjucksService = class NunjucksService {
|
|
|
1236
1720
|
trimBlocks: options.trimBlocks ?? true,
|
|
1237
1721
|
lstripBlocks: options.lstripBlocks ?? true
|
|
1238
1722
|
};
|
|
1239
|
-
nunjucks.
|
|
1723
|
+
nunjucks.configure(configOptions);
|
|
1240
1724
|
}
|
|
1241
|
-
return nunjucks.
|
|
1725
|
+
return nunjucks.renderString(template, data);
|
|
1242
1726
|
} catch (error) {
|
|
1243
1727
|
throw new TemplateRenderException("Nunjucks", `Nunjucks rendering failed: ${String(error)}`, { cause: error });
|
|
1244
1728
|
}
|
|
1245
1729
|
}
|
|
1246
1730
|
renderFile(filePath, data = {}, options) {
|
|
1731
|
+
const nunjucks = this.#engine;
|
|
1247
1732
|
try {
|
|
1248
1733
|
if (options) {
|
|
1249
1734
|
const configOptions = {
|
|
@@ -1253,21 +1738,25 @@ let NunjucksService = class NunjucksService {
|
|
|
1253
1738
|
trimBlocks: options.trimBlocks ?? true,
|
|
1254
1739
|
lstripBlocks: options.lstripBlocks ?? true
|
|
1255
1740
|
};
|
|
1256
|
-
nunjucks.
|
|
1741
|
+
nunjucks.configure(configOptions);
|
|
1257
1742
|
}
|
|
1258
|
-
return nunjucks.
|
|
1743
|
+
return nunjucks.render(filePath, data);
|
|
1259
1744
|
} catch (error) {
|
|
1260
1745
|
throw new TemplateRenderException("Nunjucks", `Nunjucks file rendering failed: ${String(error)}`, { cause: error });
|
|
1261
1746
|
}
|
|
1262
1747
|
}
|
|
1263
1748
|
};
|
|
1264
|
-
NunjucksService = __decorate([(0, _nestjs_common.Injectable)()
|
|
1265
|
-
|
|
1266
|
-
//#region src/puppeteer/engines/pug/pug.service.ts
|
|
1749
|
+
NunjucksService = __decorate([(0, _nestjs_common.Injectable)()], NunjucksService);
|
|
1750
|
+
// src/puppeteer/engines/pug/pug.service.ts
|
|
1267
1751
|
let PugService = class PugService {
|
|
1752
|
+
#pug;
|
|
1753
|
+
get #engine() {
|
|
1754
|
+
return this.#pug ??= loadEngine("pug", "Pug");
|
|
1755
|
+
}
|
|
1268
1756
|
render(template, data = {}, options) {
|
|
1757
|
+
const engine = this.#engine;
|
|
1269
1758
|
try {
|
|
1270
|
-
return
|
|
1759
|
+
return engine.compile(template, { ...options })(data);
|
|
1271
1760
|
} catch (error) {
|
|
1272
1761
|
throw new TemplateRenderException("Pug", `Pug rendering failed: ${String(error)}`, { cause: error });
|
|
1273
1762
|
}
|
|
@@ -1277,21 +1766,21 @@ let PugService = class PugService {
|
|
|
1277
1766
|
const template = (0, node_fs.readFileSync)(filePath, "utf-8");
|
|
1278
1767
|
return this.render(template, data, options);
|
|
1279
1768
|
} catch (error) {
|
|
1769
|
+
if (error instanceof EngineNotAvailableException) throw error;
|
|
1280
1770
|
throw new TemplateRenderException("Pug", `Pug file rendering failed: ${String(error)}`, { cause: error });
|
|
1281
1771
|
}
|
|
1282
1772
|
}
|
|
1283
1773
|
};
|
|
1284
1774
|
PugService = __decorate([(0, _nestjs_common.Injectable)()], PugService);
|
|
1285
|
-
|
|
1286
|
-
//#region src/puppeteer/libs/requireService.utils.ts
|
|
1775
|
+
// src/puppeteer/libs/requireService.utils.ts
|
|
1287
1776
|
function requireService(service, name) {
|
|
1288
1777
|
if (!service) throw new EngineNotAvailableException(name);
|
|
1289
1778
|
return service;
|
|
1290
1779
|
}
|
|
1291
|
-
|
|
1292
|
-
//#region src/puppeteer/puppeteer.service.ts
|
|
1780
|
+
// src/puppeteer/puppeteer.service.ts
|
|
1293
1781
|
let PuppeteerService = class PuppeteerService {
|
|
1294
|
-
#
|
|
1782
|
+
#renderer;
|
|
1783
|
+
#jobs;
|
|
1295
1784
|
#options;
|
|
1296
1785
|
#hbsService;
|
|
1297
1786
|
#mjmlService;
|
|
@@ -1300,8 +1789,10 @@ let PuppeteerService = class PuppeteerService {
|
|
|
1300
1789
|
#nunjucksService;
|
|
1301
1790
|
#etaService;
|
|
1302
1791
|
#mustacheService;
|
|
1303
|
-
|
|
1304
|
-
|
|
1792
|
+
#liquidService;
|
|
1793
|
+
constructor(renderer, jobs, options, hbsService, mjmlService, pugService, ejsService, nunjucksService, etaService, mustacheService, liquidService) {
|
|
1794
|
+
this.#renderer = renderer;
|
|
1795
|
+
this.#jobs = jobs;
|
|
1305
1796
|
this.#options = options;
|
|
1306
1797
|
this.#hbsService = hbsService;
|
|
1307
1798
|
this.#mjmlService = mjmlService;
|
|
@@ -1310,6 +1801,7 @@ let PuppeteerService = class PuppeteerService {
|
|
|
1310
1801
|
this.#nunjucksService = nunjucksService;
|
|
1311
1802
|
this.#etaService = etaService;
|
|
1312
1803
|
this.#mustacheService = mustacheService;
|
|
1804
|
+
this.#liquidService = liquidService;
|
|
1313
1805
|
}
|
|
1314
1806
|
#limit = pLimit(3);
|
|
1315
1807
|
async generatePdfFromHtml(html, options) {
|
|
@@ -1319,87 +1811,19 @@ let PuppeteerService = class PuppeteerService {
|
|
|
1319
1811
|
const job = this.#limit(async () => {
|
|
1320
1812
|
signal?.throwIfAborted();
|
|
1321
1813
|
started = true;
|
|
1322
|
-
const
|
|
1323
|
-
|
|
1324
|
-
const headless = mergePuppeteerOptions.headless ?? true;
|
|
1325
|
-
const executablePath = mergePuppeteerOptions.executablePath || void 0;
|
|
1326
|
-
const args = mergePuppeteerOptions.extraPuppeteerArgs || [
|
|
1327
|
-
"--autoplay-policy=user-gesture-required",
|
|
1328
|
-
"--disable-background-networking",
|
|
1329
|
-
"--disable-background-timer-throttling",
|
|
1330
|
-
"--disable-backgrounding-occluded-windows",
|
|
1331
|
-
"--disable-breakpad",
|
|
1332
|
-
"--disable-client-side-phishing-detection",
|
|
1333
|
-
"--disable-component-update",
|
|
1334
|
-
"--disable-default-apps",
|
|
1335
|
-
"--disable-dev-shm-usage",
|
|
1336
|
-
"--disable-domain-reliability",
|
|
1337
|
-
"--disable-extensions",
|
|
1338
|
-
"--disable-features=AudioServiceOutOfProcess",
|
|
1339
|
-
"--disable-hang-monitor",
|
|
1340
|
-
"--disable-ipc-flooding-protection",
|
|
1341
|
-
"--disable-notifications",
|
|
1342
|
-
"--disable-offer-store-unmasked-wallet-cards",
|
|
1343
|
-
"--disable-print-preview",
|
|
1344
|
-
"--disable-prompt-on-repost",
|
|
1345
|
-
"--disable-renderer-backgrounding",
|
|
1346
|
-
"--disable-setuid-sandbox",
|
|
1347
|
-
"--disable-speech-api",
|
|
1348
|
-
"--disable-sync",
|
|
1349
|
-
"--hide-scrollbars",
|
|
1350
|
-
"--ignore-gpu-blacklist",
|
|
1351
|
-
"--metrics-recording-only",
|
|
1352
|
-
"--mute-audio",
|
|
1353
|
-
"--no-default-browser-check",
|
|
1354
|
-
"--no-first-run",
|
|
1355
|
-
"--no-pings",
|
|
1356
|
-
"--password-store=basic",
|
|
1357
|
-
"--use-gl=swiftshader",
|
|
1358
|
-
"--use-mock-keychain",
|
|
1359
|
-
"--disable-accelerated-2d-canvas",
|
|
1360
|
-
"--no-zygote",
|
|
1361
|
-
"--disable-gpu"
|
|
1362
|
-
];
|
|
1363
|
-
this.#browserService.markJobStarted();
|
|
1364
|
-
let context = null;
|
|
1365
|
-
let closing;
|
|
1366
|
-
const onAbort = () => {
|
|
1367
|
-
if (!context) return;
|
|
1368
|
-
closing = context.close();
|
|
1369
|
-
closing.catch(() => void 0);
|
|
1370
|
-
};
|
|
1371
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1814
|
+
const mergedOptions = mergePuppeteerParameters(this.#options, options);
|
|
1815
|
+
this.#jobs.markJobStarted();
|
|
1372
1816
|
try {
|
|
1373
|
-
|
|
1374
|
-
signal?.throwIfAborted();
|
|
1375
|
-
const page = await context.newPage();
|
|
1376
|
-
if (mergePuppeteerOptions.security) await installRequestGuard(context, page, mergePuppeteerOptions.security);
|
|
1377
|
-
const pdfOptions = mergePuppeteerOptions.pdfOptions ?? { format: "A4" };
|
|
1378
|
-
await page.setContent(html, { waitUntil: "domcontentloaded" });
|
|
1379
|
-
await page.emulateMediaType("screen");
|
|
1380
|
-
await page.waitForNetworkIdle({
|
|
1381
|
-
idleTime: 500,
|
|
1382
|
-
timeout: 3e4
|
|
1383
|
-
});
|
|
1384
|
-
/* v8 ignore next */
|
|
1385
|
-
await page.evaluate(() => document.fonts.ready);
|
|
1386
|
-
const pdf = await page.pdf(pdfOptions);
|
|
1817
|
+
const pdf = await this.#renderer.render(html, mergedOptions, signal);
|
|
1387
1818
|
signal?.throwIfAborted();
|
|
1388
|
-
return
|
|
1819
|
+
return mergedOptions.watermark ? await addWatermark(pdf, mergedOptions.watermark) : pdf;
|
|
1389
1820
|
} catch (e) {
|
|
1390
1821
|
if (signal?.aborted) throw signal.reason;
|
|
1391
1822
|
_nestjs_common.Logger.error(e);
|
|
1392
1823
|
if (e instanceof NestjsPdfException) throw e;
|
|
1393
1824
|
throw new PdfGenerationException(`PDF generation failed: ${String(e)}`, { cause: e });
|
|
1394
1825
|
} finally {
|
|
1395
|
-
|
|
1396
|
-
if (context) try {
|
|
1397
|
-
if (closing) await closing;
|
|
1398
|
-
else await context.close();
|
|
1399
|
-
} catch (error) {
|
|
1400
|
-
_nestjs_common.Logger.error(error);
|
|
1401
|
-
}
|
|
1402
|
-
await this.#browserService.markJobFinished();
|
|
1826
|
+
await this.#jobs.markJobFinished();
|
|
1403
1827
|
}
|
|
1404
1828
|
});
|
|
1405
1829
|
if (!signal) return job;
|
|
@@ -1472,19 +1896,31 @@ let PuppeteerService = class PuppeteerService {
|
|
|
1472
1896
|
const html = requireService(this.#mustacheService, "Mustache").renderFile(file, data, options?.mustacheOptions ?? this.#options.mustacheOptions);
|
|
1473
1897
|
return this.generatePdfFromHtml(html, options);
|
|
1474
1898
|
}
|
|
1899
|
+
async generatePdfFromLiquidString(template, data = {}, options) {
|
|
1900
|
+
const html = requireService(this.#liquidService, "Liquid").render(template, data, options?.liquidOptions ?? this.#options.liquidOptions);
|
|
1901
|
+
return this.generatePdfFromHtml(html, options);
|
|
1902
|
+
}
|
|
1903
|
+
async generatePdfFromLiquidFile(file, data = {}, options) {
|
|
1904
|
+
const html = requireService(this.#liquidService, "Liquid").renderFile(file, data, options?.liquidOptions ?? this.#options.liquidOptions);
|
|
1905
|
+
return this.generatePdfFromHtml(html, options);
|
|
1906
|
+
}
|
|
1475
1907
|
};
|
|
1476
1908
|
PuppeteerService = __decorate([
|
|
1477
1909
|
(0, _nestjs_common.Injectable)(),
|
|
1478
|
-
__decorateParam(
|
|
1479
|
-
__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)),
|
|
1480
1913
|
__decorateParam(3, (0, _nestjs_common.Optional)()),
|
|
1481
1914
|
__decorateParam(4, (0, _nestjs_common.Optional)()),
|
|
1482
1915
|
__decorateParam(5, (0, _nestjs_common.Optional)()),
|
|
1483
1916
|
__decorateParam(6, (0, _nestjs_common.Optional)()),
|
|
1484
1917
|
__decorateParam(7, (0, _nestjs_common.Optional)()),
|
|
1485
1918
|
__decorateParam(8, (0, _nestjs_common.Optional)()),
|
|
1919
|
+
__decorateParam(9, (0, _nestjs_common.Optional)()),
|
|
1920
|
+
__decorateParam(10, (0, _nestjs_common.Optional)()),
|
|
1486
1921
|
__decorateMetadata("design:paramtypes", [
|
|
1487
|
-
|
|
1922
|
+
Object,
|
|
1923
|
+
Object,
|
|
1488
1924
|
Object,
|
|
1489
1925
|
typeof HandlebarsService === "undefined" ? Object : HandlebarsService,
|
|
1490
1926
|
typeof MjmlService === "undefined" ? Object : MjmlService,
|
|
@@ -1492,11 +1928,11 @@ PuppeteerService = __decorate([
|
|
|
1492
1928
|
typeof EjsService === "undefined" ? Object : EjsService,
|
|
1493
1929
|
typeof NunjucksService === "undefined" ? Object : NunjucksService,
|
|
1494
1930
|
typeof EtaService === "undefined" ? Object : EtaService,
|
|
1495
|
-
typeof MustacheService === "undefined" ? Object : MustacheService
|
|
1931
|
+
typeof MustacheService === "undefined" ? Object : MustacheService,
|
|
1932
|
+
typeof LiquidService === "undefined" ? Object : LiquidService
|
|
1496
1933
|
])
|
|
1497
1934
|
], PuppeteerService);
|
|
1498
|
-
|
|
1499
|
-
//#region src/nestjs-pdf.service.ts
|
|
1935
|
+
// src/nestjs-pdf.service.ts
|
|
1500
1936
|
let NestjsPdfService = class NestjsPdfService {
|
|
1501
1937
|
#puppeteerService;
|
|
1502
1938
|
constructor(puppeteerService) {
|
|
@@ -1650,6 +2086,26 @@ let NestjsPdfService = class NestjsPdfService {
|
|
|
1650
2086
|
return this.#puppeteerService.generatePdfFromMustacheFile(file, data, options);
|
|
1651
2087
|
}
|
|
1652
2088
|
/**
|
|
2089
|
+
* @param template Liquid template string
|
|
2090
|
+
* @param data Data to inject into the template
|
|
2091
|
+
* @param options PDF generation options (optional)
|
|
2092
|
+
* @returns PDF generated from the provided Liquid template with data applied
|
|
2093
|
+
* @description This method generates a PDF from a Liquid template provided as a string. Liquid is a safe, Shopify-compatible template language with filters, tags, partials and layouts. The data to inject into the template is passed in the `data` object, which is used to render the template before converting it to PDF. PDF generation options can be customized by passing a `PuppeteerParameters` object as the third argument.
|
|
2094
|
+
*/
|
|
2095
|
+
generatePdfFromLiquidString(template, data = {}, options) {
|
|
2096
|
+
return this.#puppeteerService.generatePdfFromLiquidString(template, data, options);
|
|
2097
|
+
}
|
|
2098
|
+
/**
|
|
2099
|
+
* @param file Path to the Liquid template file
|
|
2100
|
+
* @param data Data to inject into the template
|
|
2101
|
+
* @param options PDF generation options (optional)
|
|
2102
|
+
* @returns PDF generated from the Liquid template at the provided file path with data applied
|
|
2103
|
+
* @description This method generates a PDF from a Liquid template located at the specified file path. The file path is passed as a string in the `file` parameter. The data to inject into the template is passed in the `data` object, which is used to render the template before converting it to PDF. PDF generation options can be customized by passing a `PuppeteerParameters` object as the third argument.
|
|
2104
|
+
*/
|
|
2105
|
+
generatePdfFromLiquidFile(file, data = {}, options) {
|
|
2106
|
+
return this.#puppeteerService.generatePdfFromLiquidFile(file, data, options);
|
|
2107
|
+
}
|
|
2108
|
+
/**
|
|
1653
2109
|
* @param pdf The PDF bytes to modify
|
|
1654
2110
|
* @param fieldName The name of the signature field to add (default: 'SignatureDebtor')
|
|
1655
2111
|
* @param anchorText The text anchor to locate the signature field position (default: '__SIG_DEBTOR_ANCHOR__')
|
|
@@ -1696,9 +2152,14 @@ let NestjsPdfService = class NestjsPdfService {
|
|
|
1696
2152
|
}
|
|
1697
2153
|
};
|
|
1698
2154
|
NestjsPdfService = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof PuppeteerService === "undefined" ? Object : PuppeteerService])], NestjsPdfService);
|
|
1699
|
-
|
|
1700
|
-
//#region src/puppeteer/puppeteer.module.ts
|
|
2155
|
+
// src/puppeteer/puppeteer.module.ts
|
|
1701
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
|
+
};
|
|
1702
2163
|
let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
1703
2164
|
#browserService;
|
|
1704
2165
|
#pdfParams;
|
|
@@ -1707,7 +2168,12 @@ let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
|
1707
2168
|
this.#pdfParams = pdfParams;
|
|
1708
2169
|
}
|
|
1709
2170
|
async onModuleInit() {
|
|
1710
|
-
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
|
+
}
|
|
1711
2177
|
}
|
|
1712
2178
|
static forRoot(pdfParameters) {
|
|
1713
2179
|
return {
|
|
@@ -1723,7 +2189,8 @@ let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
|
1723
2189
|
EjsService,
|
|
1724
2190
|
NunjucksService,
|
|
1725
2191
|
EtaService,
|
|
1726
|
-
MustacheService
|
|
2192
|
+
MustacheService,
|
|
2193
|
+
LiquidService
|
|
1727
2194
|
],
|
|
1728
2195
|
exports: [
|
|
1729
2196
|
PuppeteerService,
|
|
@@ -1732,7 +2199,8 @@ let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
|
1732
2199
|
EjsService,
|
|
1733
2200
|
NunjucksService,
|
|
1734
2201
|
EtaService,
|
|
1735
|
-
MustacheService
|
|
2202
|
+
MustacheService,
|
|
2203
|
+
LiquidService
|
|
1736
2204
|
]
|
|
1737
2205
|
};
|
|
1738
2206
|
}
|
|
@@ -1749,13 +2217,15 @@ let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
|
1749
2217
|
pdfParamsProvider,
|
|
1750
2218
|
PuppeteerService,
|
|
1751
2219
|
BrowserService,
|
|
2220
|
+
pdfRendererProvider,
|
|
1752
2221
|
HandlebarsService,
|
|
1753
2222
|
MjmlService,
|
|
1754
2223
|
PugService,
|
|
1755
2224
|
EjsService,
|
|
1756
2225
|
NunjucksService,
|
|
1757
2226
|
EtaService,
|
|
1758
|
-
MustacheService
|
|
2227
|
+
MustacheService,
|
|
2228
|
+
LiquidService
|
|
1759
2229
|
],
|
|
1760
2230
|
exports: [
|
|
1761
2231
|
PuppeteerService,
|
|
@@ -1764,7 +2234,8 @@ let PuppeteerModule = _PuppeteerModule = class PuppeteerModule {
|
|
|
1764
2234
|
EjsService,
|
|
1765
2235
|
NunjucksService,
|
|
1766
2236
|
EtaService,
|
|
1767
|
-
MustacheService
|
|
2237
|
+
MustacheService,
|
|
2238
|
+
LiquidService
|
|
1768
2239
|
]
|
|
1769
2240
|
};
|
|
1770
2241
|
}
|
|
@@ -1774,12 +2245,14 @@ PuppeteerModule = _PuppeteerModule = __decorate([
|
|
|
1774
2245
|
providers: [
|
|
1775
2246
|
PuppeteerService,
|
|
1776
2247
|
BrowserService,
|
|
2248
|
+
pdfRendererProvider,
|
|
1777
2249
|
MjmlService,
|
|
1778
2250
|
PugService,
|
|
1779
2251
|
EjsService,
|
|
1780
2252
|
NunjucksService,
|
|
1781
2253
|
EtaService,
|
|
1782
|
-
MustacheService
|
|
2254
|
+
MustacheService,
|
|
2255
|
+
LiquidService
|
|
1783
2256
|
],
|
|
1784
2257
|
exports: [
|
|
1785
2258
|
PuppeteerService,
|
|
@@ -1788,14 +2261,15 @@ PuppeteerModule = _PuppeteerModule = __decorate([
|
|
|
1788
2261
|
EjsService,
|
|
1789
2262
|
NunjucksService,
|
|
1790
2263
|
EtaService,
|
|
1791
|
-
MustacheService
|
|
2264
|
+
MustacheService,
|
|
2265
|
+
LiquidService
|
|
1792
2266
|
]
|
|
1793
2267
|
}),
|
|
2268
|
+
__decorateParam(0, (0, _nestjs_common.Inject)(BrowserService)),
|
|
1794
2269
|
__decorateParam(1, (0, _nestjs_common.Inject)(PDF_PARAMETERS)),
|
|
1795
|
-
__decorateMetadata("design:paramtypes", [
|
|
2270
|
+
__decorateMetadata("design:paramtypes", [Object, Object])
|
|
1796
2271
|
], PuppeteerModule);
|
|
1797
|
-
|
|
1798
|
-
//#region src/nestjs-pdf.module.ts
|
|
2272
|
+
// src/nestjs-pdf.module.ts
|
|
1799
2273
|
var _NestjsPdfModule;
|
|
1800
2274
|
let NestjsPdfModule = _NestjsPdfModule = class NestjsPdfModule {
|
|
1801
2275
|
static forRoot(options) {
|
|
@@ -1816,7 +2290,6 @@ let NestjsPdfModule = _NestjsPdfModule = class NestjsPdfModule {
|
|
|
1816
2290
|
}
|
|
1817
2291
|
};
|
|
1818
2292
|
NestjsPdfModule = _NestjsPdfModule = __decorate([(0, _nestjs_common.Module)({})], NestjsPdfModule);
|
|
1819
|
-
//#endregion
|
|
1820
2293
|
exports.BrowserInstallationException = BrowserInstallationException;
|
|
1821
2294
|
exports.BrowserUnavailableException = BrowserUnavailableException;
|
|
1822
2295
|
Object.defineProperty(exports, "EjsService", {
|
|
@@ -1838,6 +2311,12 @@ Object.defineProperty(exports, "HandlebarsService", {
|
|
|
1838
2311
|
return HandlebarsService;
|
|
1839
2312
|
}
|
|
1840
2313
|
});
|
|
2314
|
+
Object.defineProperty(exports, "LiquidService", {
|
|
2315
|
+
enumerable: true,
|
|
2316
|
+
get: function() {
|
|
2317
|
+
return LiquidService;
|
|
2318
|
+
}
|
|
2319
|
+
});
|
|
1841
2320
|
Object.defineProperty(exports, "MjmlService", {
|
|
1842
2321
|
enumerable: true,
|
|
1843
2322
|
get: function() {
|
|
@@ -1889,6 +2368,7 @@ Object.defineProperty(exports, "PuppeteerService", {
|
|
|
1889
2368
|
return PuppeteerService;
|
|
1890
2369
|
}
|
|
1891
2370
|
});
|
|
2371
|
+
exports.RendererConfigurationException = RendererConfigurationException;
|
|
1892
2372
|
exports.SignatureDependencyException = SignatureDependencyException;
|
|
1893
2373
|
exports.SignaturePlacementException = SignaturePlacementException;
|
|
1894
2374
|
exports.TemplateConfigurationException = TemplateConfigurationException;
|