@shad0wz7/nestjs-pdf 2.5.0 → 2.5.1
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 +3 -1
- package/dist/index.cjs +255 -255
- package/dist/index.d.cts +46 -169
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +53 -176
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +255 -255
- package/dist/index.mjs.map +1 -1
- package/package.json +107 -86
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# nestjs-pdf
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/%40shad0wz7%2Fnestjs-pdf)
|
|
4
|
+
[](https://github.com/ShadowZ11/nestjs-pdf?tab=MIT-1-ov-file)
|
|
4
5
|
[](https://www.npmjs.com/package/%40shad0wz7%2Fnestjs-pdf)
|
|
5
6
|
[](https://github.com/Shadowz11/nestjs-pdf/actions/workflows/ci.yml)
|
|
6
7
|
[](https://codecov.io/github/ShadowZ11/nestjs-pdf)
|
|
7
|
-
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
A NestJS library to generate and manipulate PDFs using Puppeteer and multiple template engines, including Handlebars, EJS, Pug, MJML, Nunjucks, Eta and Mustache.
|
|
10
12
|
|
package/dist/index.cjs
CHANGED
|
@@ -22,24 +22,185 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
enumerable: true
|
|
23
23
|
}) : target, mod));
|
|
24
24
|
//#endregion
|
|
25
|
-
let _nestjs_common = require("@nestjs/common");
|
|
26
|
-
let node_fs = require("node:fs");
|
|
27
25
|
let node_path = require("node:path");
|
|
28
|
-
let
|
|
29
|
-
let
|
|
30
|
-
let
|
|
26
|
+
let _nestjs_common = require("@nestjs/common");
|
|
27
|
+
let pdf_lib = require("pdf-lib");
|
|
28
|
+
let _gboutte_nestjs_hbs = require("@gboutte/nestjs-hbs");
|
|
31
29
|
let p_limit = require("p-limit");
|
|
32
30
|
p_limit = __toESM(p_limit);
|
|
33
|
-
let
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
let
|
|
31
|
+
let deepmerge_ts = require("deepmerge-ts");
|
|
32
|
+
let node_fs = require("node:fs");
|
|
33
|
+
let _puppeteer_browsers = require("@puppeteer/browsers");
|
|
34
|
+
let puppeteer = require("puppeteer");
|
|
37
35
|
let ejs = require("ejs");
|
|
38
|
-
let nunjucks = require("nunjucks");
|
|
39
36
|
let eta = require("eta");
|
|
37
|
+
let mjml = require("mjml");
|
|
38
|
+
mjml = __toESM(mjml);
|
|
40
39
|
let mustache = require("mustache");
|
|
41
40
|
mustache = __toESM(mustache);
|
|
42
|
-
let
|
|
41
|
+
let nunjucks = require("nunjucks");
|
|
42
|
+
let pug = require("pug");
|
|
43
|
+
//#region src/helpers/getRelativePath.helper.ts
|
|
44
|
+
/**
|
|
45
|
+
* Get the relative path to a value from the module directory.
|
|
46
|
+
* @param moduleDir the path of the module, typically __dirname
|
|
47
|
+
* @param relativeToModule the path to the value relative to the module directory
|
|
48
|
+
* @returns the relative path from the current working directory to the value
|
|
49
|
+
* @example
|
|
50
|
+
* getRelativePathToValue(__dirname, './templates/my-template.hbs');
|
|
51
|
+
* // returns 'context/pdf/templates/my-template.hbs' if the current working directory is '/
|
|
52
|
+
*/
|
|
53
|
+
function getRelativePathToValue(moduleDir, relativeToModule) {
|
|
54
|
+
const fullTemplatePath = (0, node_path.resolve)(moduleDir, relativeToModule);
|
|
55
|
+
return (0, node_path.relative)(process.cwd(), fullTemplatePath);
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/helpers/signature.helper.ts
|
|
59
|
+
let pdfjsPromise;
|
|
60
|
+
async function loadPdfjs() {
|
|
61
|
+
if (!pdfjsPromise) try {
|
|
62
|
+
pdfjsPromise = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
63
|
+
} catch (error) {
|
|
64
|
+
pdfjsPromise = void 0;
|
|
65
|
+
throw new Error([
|
|
66
|
+
"Failed to load pdfjs-dist.",
|
|
67
|
+
"If you use anchor-based signature placement in Node.js, make sure @napi-rs/canvas is installed.",
|
|
68
|
+
"Try: npm install @napi-rs/canvas",
|
|
69
|
+
"",
|
|
70
|
+
`Original error: ${error instanceof Error ? error.message : String(error)}`
|
|
71
|
+
].join("\n"), { cause: error });
|
|
72
|
+
}
|
|
73
|
+
return pdfjsPromise;
|
|
74
|
+
}
|
|
75
|
+
function toU8(input) {
|
|
76
|
+
return new Uint8Array(input);
|
|
77
|
+
}
|
|
78
|
+
async function findAnchorPosition(pdfBytes, anchorText) {
|
|
79
|
+
const pdfjsLib = await loadPdfjs();
|
|
80
|
+
const loadingTask = pdfjsLib.getDocument({ data: pdfBytes });
|
|
81
|
+
try {
|
|
82
|
+
const pdf = await loadingTask.promise;
|
|
83
|
+
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
|
84
|
+
const page = await pdf.getPage(pageNum);
|
|
85
|
+
const viewport = page.getViewport({ scale: 1 });
|
|
86
|
+
const textContent = await page.getTextContent();
|
|
87
|
+
for (const itemRaw of textContent.items) {
|
|
88
|
+
const item = itemRaw;
|
|
89
|
+
if (!item.str?.includes(anchorText)) continue;
|
|
90
|
+
const [_a, _b, _c, _d, e, f] = pdfjsLib.Util.transform(viewport.transform, item.transform);
|
|
91
|
+
const x = e;
|
|
92
|
+
const y = viewport.height - f;
|
|
93
|
+
return {
|
|
94
|
+
pageIndex: pageNum - 1,
|
|
95
|
+
x,
|
|
96
|
+
y,
|
|
97
|
+
pageWidth: viewport.width,
|
|
98
|
+
pageHeight: viewport.height
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
} finally {
|
|
104
|
+
await loadingTask.destroy();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function addSignatureFieldAt(pdfDoc, pageIndex, opts) {
|
|
108
|
+
const { fieldName, x, y, width, height } = opts;
|
|
109
|
+
const context = pdfDoc.context;
|
|
110
|
+
const page = pdfDoc.getPages()[pageIndex];
|
|
111
|
+
if (!page) throw new Error(`Page ${pageIndex} not found`);
|
|
112
|
+
const rectArray = context.obj([
|
|
113
|
+
pdf_lib.PDFNumber.of(x),
|
|
114
|
+
pdf_lib.PDFNumber.of(y),
|
|
115
|
+
pdf_lib.PDFNumber.of(x + width),
|
|
116
|
+
pdf_lib.PDFNumber.of(y + height)
|
|
117
|
+
]);
|
|
118
|
+
const widgetDict = context.obj({
|
|
119
|
+
Type: pdf_lib.PDFName.of("Annot"),
|
|
120
|
+
Subtype: pdf_lib.PDFName.of("Widget"),
|
|
121
|
+
Rect: rectArray,
|
|
122
|
+
F: pdf_lib.PDFNumber.of(4),
|
|
123
|
+
P: page.ref
|
|
124
|
+
});
|
|
125
|
+
const widgetRef = context.register(widgetDict);
|
|
126
|
+
const fieldDict = context.obj({
|
|
127
|
+
FT: pdf_lib.PDFName.of("Sig"),
|
|
128
|
+
T: pdf_lib.PDFString.of(fieldName),
|
|
129
|
+
Ff: pdf_lib.PDFNumber.of(0),
|
|
130
|
+
Kids: context.obj([widgetRef])
|
|
131
|
+
});
|
|
132
|
+
const fieldRef = context.register(fieldDict);
|
|
133
|
+
widgetDict.set(pdf_lib.PDFName.of("Parent"), fieldRef);
|
|
134
|
+
let annots = page.node.lookupMaybe(pdf_lib.PDFName.of("Annots"), pdf_lib.PDFArray);
|
|
135
|
+
if (!annots) {
|
|
136
|
+
annots = context.obj([]);
|
|
137
|
+
page.node.set(pdf_lib.PDFName.of("Annots"), annots);
|
|
138
|
+
}
|
|
139
|
+
annots.push(widgetRef);
|
|
140
|
+
let acroForm = pdfDoc.catalog.lookupMaybe(pdf_lib.PDFName.of("AcroForm"), pdf_lib.PDFDict);
|
|
141
|
+
if (!acroForm) {
|
|
142
|
+
acroForm = context.obj({
|
|
143
|
+
Fields: context.obj([]),
|
|
144
|
+
SigFlags: pdf_lib.PDFNumber.of(3)
|
|
145
|
+
});
|
|
146
|
+
const acroFormRef = context.register(acroForm);
|
|
147
|
+
pdfDoc.catalog.set(pdf_lib.PDFName.of("AcroForm"), acroFormRef);
|
|
148
|
+
}
|
|
149
|
+
let fields = acroForm.lookupMaybe(pdf_lib.PDFName.of("Fields"), pdf_lib.PDFArray);
|
|
150
|
+
if (!fields) {
|
|
151
|
+
fields = context.obj([]);
|
|
152
|
+
acroForm.set(pdf_lib.PDFName.of("Fields"), fields);
|
|
153
|
+
}
|
|
154
|
+
fields.push(fieldRef);
|
|
155
|
+
return {
|
|
156
|
+
fieldRef,
|
|
157
|
+
widgetRef
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor", anchorText = "__SIG_DEBTOR_ANCHOR__") {
|
|
161
|
+
const bytes = toU8(pdf);
|
|
162
|
+
const anchor = await findAnchorPosition(bytes.slice(), anchorText);
|
|
163
|
+
const pdfDoc = await pdf_lib.PDFDocument.load(bytes);
|
|
164
|
+
const sigWidth = 240;
|
|
165
|
+
const sigHeight = 50;
|
|
166
|
+
if (anchor) {
|
|
167
|
+
const pageIndex = anchor.pageIndex;
|
|
168
|
+
const { width: pw, height: ph } = pdfDoc.getPages()[pageIndex].getSize();
|
|
169
|
+
const padX = 40;
|
|
170
|
+
const padY = 7;
|
|
171
|
+
let x = anchor.x - sigWidth / 2 + padX;
|
|
172
|
+
let y = anchor.y - sigHeight + padY;
|
|
173
|
+
const margin = 10;
|
|
174
|
+
x = Math.max(margin, Math.min(x, pw - sigWidth - margin));
|
|
175
|
+
y = Math.max(margin, Math.min(y, ph - sigHeight - margin));
|
|
176
|
+
addSignatureFieldAt(pdfDoc, anchor.pageIndex, {
|
|
177
|
+
fieldName,
|
|
178
|
+
x,
|
|
179
|
+
y,
|
|
180
|
+
width: sigWidth,
|
|
181
|
+
height: sigHeight
|
|
182
|
+
});
|
|
183
|
+
} else {
|
|
184
|
+
const pages = pdfDoc.getPages();
|
|
185
|
+
const pageIndex = pages.length - 1;
|
|
186
|
+
const { width: pageWidth } = pages[pageIndex].getSize();
|
|
187
|
+
addSignatureFieldAt(pdfDoc, pageIndex, {
|
|
188
|
+
fieldName,
|
|
189
|
+
x: (pageWidth - sigWidth) / 2,
|
|
190
|
+
y: 90,
|
|
191
|
+
width: sigWidth,
|
|
192
|
+
height: sigHeight
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return await pdfDoc.save();
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/helpers/deepMergePdfparams.ts
|
|
199
|
+
function mergePuppeteerParameters(defaults, overrides) {
|
|
200
|
+
if (!overrides) return { ...defaults };
|
|
201
|
+
return (0, deepmerge_ts.deepmerge)(defaults, overrides);
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
43
204
|
//#region src/helpers/tokens.ts
|
|
44
205
|
const PDF_PARAMETERS = "PDF_PARAMETERS";
|
|
45
206
|
const HANDLEBARS_PARAMETERS = "HANDLEBARS_PARAMETERS";
|
|
@@ -271,8 +432,8 @@ let BrowserService = class BrowserService {
|
|
|
271
432
|
this.useLockedBrowser = useLockedBrowser;
|
|
272
433
|
}
|
|
273
434
|
async hasBrowserInstalled(browser, buildId) {
|
|
274
|
-
return (await (0, _puppeteer_browsers.getInstalledBrowsers)({ cacheDir: this.cacheDir })).find((
|
|
275
|
-
return
|
|
435
|
+
return (await (0, _puppeteer_browsers.getInstalledBrowsers)({ cacheDir: this.cacheDir })).find((insBrowser) => {
|
|
436
|
+
return insBrowser.browser === browser && insBrowser.buildId === buildId;
|
|
276
437
|
}) !== void 0;
|
|
277
438
|
}
|
|
278
439
|
async getExecutablePath() {
|
|
@@ -285,8 +446,8 @@ let BrowserService = class BrowserService {
|
|
|
285
446
|
_nestjs_common.Logger.log(`Using locked browser ${buildId}`, "NestJsPdf");
|
|
286
447
|
}
|
|
287
448
|
buildId ??= await (0, _puppeteer_browsers.resolveBuildId)(browser, browserPlatform, versionTag);
|
|
288
|
-
const installedBrowser = (await (0, _puppeteer_browsers.getInstalledBrowsers)({ cacheDir: this.cacheDir })).find((
|
|
289
|
-
return
|
|
449
|
+
const installedBrowser = (await (0, _puppeteer_browsers.getInstalledBrowsers)({ cacheDir: this.cacheDir })).find((insBrowser) => {
|
|
450
|
+
return insBrowser.browser === browser && insBrowser.buildId === buildId;
|
|
290
451
|
});
|
|
291
452
|
if (installedBrowser === void 0) {
|
|
292
453
|
const newinstalledBrowser = await this.install();
|
|
@@ -333,45 +494,6 @@ BrowserService = __decorate([
|
|
|
333
494
|
__decorateMetadata("design:paramtypes", [Object])
|
|
334
495
|
], BrowserService);
|
|
335
496
|
//#endregion
|
|
336
|
-
//#region src/helpers/deepMergePdfparams.ts
|
|
337
|
-
function mergePuppeteerParameters(defaults, overrides) {
|
|
338
|
-
if (!overrides) return { ...defaults };
|
|
339
|
-
return (0, deepmerge_ts.deepmerge)(defaults, overrides);
|
|
340
|
-
}
|
|
341
|
-
//#endregion
|
|
342
|
-
//#region src/puppeteer/engines/mjml/mjml.service.ts
|
|
343
|
-
let MjmlService = class MjmlService {
|
|
344
|
-
async render(template, options) {
|
|
345
|
-
const { html } = await (0, mjml.default)(template, options);
|
|
346
|
-
return html;
|
|
347
|
-
}
|
|
348
|
-
async renderFile(filePath, options) {
|
|
349
|
-
const template = (0, node_fs.readFileSync)(filePath, "utf-8");
|
|
350
|
-
return await this.render(template, options);
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
MjmlService = __decorate([(0, _nestjs_common.Injectable)()], MjmlService);
|
|
354
|
-
//#endregion
|
|
355
|
-
//#region src/puppeteer/engines/pug/pug.service.ts
|
|
356
|
-
let PugService = class PugService {
|
|
357
|
-
render(template, data = {}, options) {
|
|
358
|
-
try {
|
|
359
|
-
return (0, pug.compile)(template, { ...options })(data);
|
|
360
|
-
} catch (error) {
|
|
361
|
-
throw new Error(`Pug rendering failed: ${String(error)}`, { cause: error });
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
renderFile(filePath, data = {}, options) {
|
|
365
|
-
try {
|
|
366
|
-
const template = (0, node_fs.readFileSync)(filePath, "utf-8");
|
|
367
|
-
return this.render(template, data, options);
|
|
368
|
-
} catch (error) {
|
|
369
|
-
throw new Error(`Pug file rendering failed: ${String(error)}`, { cause: error });
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
PugService = __decorate([(0, _nestjs_common.Injectable)()], PugService);
|
|
374
|
-
//#endregion
|
|
375
497
|
//#region src/puppeteer/engines/ejs/ejs.service.ts
|
|
376
498
|
let EjsService = class EjsService {
|
|
377
499
|
async render(template, data = {}, options) {
|
|
@@ -397,52 +519,6 @@ let EjsService = class EjsService {
|
|
|
397
519
|
};
|
|
398
520
|
EjsService = __decorate([(0, _nestjs_common.Injectable)()], EjsService);
|
|
399
521
|
//#endregion
|
|
400
|
-
//#region src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
401
|
-
let NunjucksService = class NunjucksService {
|
|
402
|
-
constructor() {
|
|
403
|
-
(0, nunjucks.configure)({
|
|
404
|
-
noCache: true,
|
|
405
|
-
trimBlocks: true,
|
|
406
|
-
lstripBlocks: true
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
render(template, data = {}, options) {
|
|
410
|
-
try {
|
|
411
|
-
if (options) {
|
|
412
|
-
const configOptions = {
|
|
413
|
-
noCache: options.noCache ?? true,
|
|
414
|
-
watch: options.watch ?? false,
|
|
415
|
-
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
416
|
-
trimBlocks: options.trimBlocks ?? true,
|
|
417
|
-
lstripBlocks: options.lstripBlocks ?? true
|
|
418
|
-
};
|
|
419
|
-
(0, nunjucks.configure)(configOptions);
|
|
420
|
-
}
|
|
421
|
-
return (0, nunjucks.renderString)(template, data);
|
|
422
|
-
} catch (error) {
|
|
423
|
-
throw new Error(`Nunjucks rendering failed: ${String(error)}`, { cause: error });
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
renderFile(filePath, data = {}, options) {
|
|
427
|
-
try {
|
|
428
|
-
if (options) {
|
|
429
|
-
const configOptions = {
|
|
430
|
-
noCache: options.noCache ?? true,
|
|
431
|
-
watch: options.watch ?? false,
|
|
432
|
-
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
433
|
-
trimBlocks: options.trimBlocks ?? true,
|
|
434
|
-
lstripBlocks: options.lstripBlocks ?? true
|
|
435
|
-
};
|
|
436
|
-
(0, nunjucks.configure)(configOptions);
|
|
437
|
-
}
|
|
438
|
-
return (0, nunjucks.render)(filePath, data);
|
|
439
|
-
} catch (error) {
|
|
440
|
-
throw new Error(`Nunjucks file rendering failed: ${String(error)}`, { cause: error });
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
NunjucksService = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [])], NunjucksService);
|
|
445
|
-
//#endregion
|
|
446
522
|
//#region src/puppeteer/engines/eta/eta.service.ts
|
|
447
523
|
let EtaService = class EtaService {
|
|
448
524
|
eta;
|
|
@@ -512,6 +588,19 @@ let EtaService = class EtaService {
|
|
|
512
588
|
};
|
|
513
589
|
EtaService = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [])], EtaService);
|
|
514
590
|
//#endregion
|
|
591
|
+
//#region src/puppeteer/engines/mjml/mjml.service.ts
|
|
592
|
+
let MjmlService = class MjmlService {
|
|
593
|
+
async render(template, options) {
|
|
594
|
+
const { html } = await (0, mjml.default)(template, options);
|
|
595
|
+
return html;
|
|
596
|
+
}
|
|
597
|
+
async renderFile(filePath, options) {
|
|
598
|
+
const template = (0, node_fs.readFileSync)(filePath, "utf-8");
|
|
599
|
+
return await this.render(template, options);
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
MjmlService = __decorate([(0, _nestjs_common.Injectable)()], MjmlService);
|
|
603
|
+
//#endregion
|
|
515
604
|
//#region src/puppeteer/engines/mustache/mustache.service.ts
|
|
516
605
|
let MustacheService = class MustacheService {
|
|
517
606
|
templateCache = /* @__PURE__ */ new Map();
|
|
@@ -570,6 +659,72 @@ let MustacheService = class MustacheService {
|
|
|
570
659
|
};
|
|
571
660
|
MustacheService = __decorate([(0, _nestjs_common.Injectable)()], MustacheService);
|
|
572
661
|
//#endregion
|
|
662
|
+
//#region src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
663
|
+
let NunjucksService = class NunjucksService {
|
|
664
|
+
constructor() {
|
|
665
|
+
(0, nunjucks.configure)({
|
|
666
|
+
noCache: true,
|
|
667
|
+
trimBlocks: true,
|
|
668
|
+
lstripBlocks: true
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
render(template, data = {}, options) {
|
|
672
|
+
try {
|
|
673
|
+
if (options) {
|
|
674
|
+
const configOptions = {
|
|
675
|
+
noCache: options.noCache ?? true,
|
|
676
|
+
watch: options.watch ?? false,
|
|
677
|
+
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
678
|
+
trimBlocks: options.trimBlocks ?? true,
|
|
679
|
+
lstripBlocks: options.lstripBlocks ?? true
|
|
680
|
+
};
|
|
681
|
+
(0, nunjucks.configure)(configOptions);
|
|
682
|
+
}
|
|
683
|
+
return (0, nunjucks.renderString)(template, data);
|
|
684
|
+
} catch (error) {
|
|
685
|
+
throw new Error(`Nunjucks rendering failed: ${String(error)}`, { cause: error });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
renderFile(filePath, data = {}, options) {
|
|
689
|
+
try {
|
|
690
|
+
if (options) {
|
|
691
|
+
const configOptions = {
|
|
692
|
+
noCache: options.noCache ?? true,
|
|
693
|
+
watch: options.watch ?? false,
|
|
694
|
+
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
695
|
+
trimBlocks: options.trimBlocks ?? true,
|
|
696
|
+
lstripBlocks: options.lstripBlocks ?? true
|
|
697
|
+
};
|
|
698
|
+
(0, nunjucks.configure)(configOptions);
|
|
699
|
+
}
|
|
700
|
+
return (0, nunjucks.render)(filePath, data);
|
|
701
|
+
} catch (error) {
|
|
702
|
+
throw new Error(`Nunjucks file rendering failed: ${String(error)}`, { cause: error });
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
NunjucksService = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [])], NunjucksService);
|
|
707
|
+
//#endregion
|
|
708
|
+
//#region src/puppeteer/engines/pug/pug.service.ts
|
|
709
|
+
let PugService = class PugService {
|
|
710
|
+
render(template, data = {}, options) {
|
|
711
|
+
try {
|
|
712
|
+
return (0, pug.compile)(template, { ...options })(data);
|
|
713
|
+
} catch (error) {
|
|
714
|
+
throw new Error(`Pug rendering failed: ${String(error)}`, { cause: error });
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
renderFile(filePath, data = {}, options) {
|
|
718
|
+
try {
|
|
719
|
+
const template = (0, node_fs.readFileSync)(filePath, "utf-8");
|
|
720
|
+
return this.render(template, data, options);
|
|
721
|
+
} catch (error) {
|
|
722
|
+
throw new Error(`Pug file rendering failed: ${String(error)}`, { cause: error });
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
PugService = __decorate([(0, _nestjs_common.Injectable)()], PugService);
|
|
727
|
+
//#endregion
|
|
573
728
|
//#region src/puppeteer/libs/requireService.utils.ts
|
|
574
729
|
function requireService(service, name) {
|
|
575
730
|
if (!service) throw new Error(`${name} service is not available. If the problem persists, open an issue in the repo.`);
|
|
@@ -750,146 +905,6 @@ PuppeteerService = __decorate([
|
|
|
750
905
|
])
|
|
751
906
|
], PuppeteerService);
|
|
752
907
|
//#endregion
|
|
753
|
-
//#region src/helpers/signature.helper.ts
|
|
754
|
-
let pdfjsPromise;
|
|
755
|
-
async function loadPdfjs() {
|
|
756
|
-
if (!pdfjsPromise) try {
|
|
757
|
-
pdfjsPromise = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
758
|
-
} catch (error) {
|
|
759
|
-
pdfjsPromise = void 0;
|
|
760
|
-
throw new Error([
|
|
761
|
-
"Failed to load pdfjs-dist.",
|
|
762
|
-
"If you use anchor-based signature placement in Node.js, make sure @napi-rs/canvas is installed.",
|
|
763
|
-
"Try: npm install @napi-rs/canvas",
|
|
764
|
-
"",
|
|
765
|
-
`Original error: ${error instanceof Error ? error.message : String(error)}`
|
|
766
|
-
].join("\n"), { cause: error });
|
|
767
|
-
}
|
|
768
|
-
return pdfjsPromise;
|
|
769
|
-
}
|
|
770
|
-
function toU8(input) {
|
|
771
|
-
return new Uint8Array(input);
|
|
772
|
-
}
|
|
773
|
-
async function findAnchorPosition(pdfBytes, anchorText) {
|
|
774
|
-
const pdfjsLib = await loadPdfjs();
|
|
775
|
-
const loadingTask = pdfjsLib.getDocument({ data: pdfBytes });
|
|
776
|
-
try {
|
|
777
|
-
const pdf = await loadingTask.promise;
|
|
778
|
-
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
|
779
|
-
const page = await pdf.getPage(pageNum);
|
|
780
|
-
const viewport = page.getViewport({ scale: 1 });
|
|
781
|
-
const textContent = await page.getTextContent();
|
|
782
|
-
for (const itemRaw of textContent.items) {
|
|
783
|
-
const item = itemRaw;
|
|
784
|
-
if (!item.str?.includes(anchorText)) continue;
|
|
785
|
-
const [_a, _b, _c, _d, e, f] = pdfjsLib.Util.transform(viewport.transform, item.transform);
|
|
786
|
-
const x = e;
|
|
787
|
-
const y = viewport.height - f;
|
|
788
|
-
return {
|
|
789
|
-
pageIndex: pageNum - 1,
|
|
790
|
-
x,
|
|
791
|
-
y,
|
|
792
|
-
pageWidth: viewport.width,
|
|
793
|
-
pageHeight: viewport.height
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
return null;
|
|
798
|
-
} finally {
|
|
799
|
-
await loadingTask.destroy();
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
function addSignatureFieldAt(pdfDoc, pageIndex, opts) {
|
|
803
|
-
const { fieldName, x, y, width, height } = opts;
|
|
804
|
-
const context = pdfDoc.context;
|
|
805
|
-
const page = pdfDoc.getPages()[pageIndex];
|
|
806
|
-
if (!page) throw new Error(`Page ${pageIndex} not found`);
|
|
807
|
-
const rectArray = context.obj([
|
|
808
|
-
pdf_lib.PDFNumber.of(x),
|
|
809
|
-
pdf_lib.PDFNumber.of(y),
|
|
810
|
-
pdf_lib.PDFNumber.of(x + width),
|
|
811
|
-
pdf_lib.PDFNumber.of(y + height)
|
|
812
|
-
]);
|
|
813
|
-
const widgetDict = context.obj({
|
|
814
|
-
Type: pdf_lib.PDFName.of("Annot"),
|
|
815
|
-
Subtype: pdf_lib.PDFName.of("Widget"),
|
|
816
|
-
Rect: rectArray,
|
|
817
|
-
F: pdf_lib.PDFNumber.of(4),
|
|
818
|
-
P: page.ref
|
|
819
|
-
});
|
|
820
|
-
const widgetRef = context.register(widgetDict);
|
|
821
|
-
const fieldDict = context.obj({
|
|
822
|
-
FT: pdf_lib.PDFName.of("Sig"),
|
|
823
|
-
T: pdf_lib.PDFString.of(fieldName),
|
|
824
|
-
Ff: pdf_lib.PDFNumber.of(0),
|
|
825
|
-
Kids: context.obj([widgetRef])
|
|
826
|
-
});
|
|
827
|
-
const fieldRef = context.register(fieldDict);
|
|
828
|
-
widgetDict.set(pdf_lib.PDFName.of("Parent"), fieldRef);
|
|
829
|
-
let annots = page.node.lookupMaybe(pdf_lib.PDFName.of("Annots"), pdf_lib.PDFArray);
|
|
830
|
-
if (!annots) {
|
|
831
|
-
annots = context.obj([]);
|
|
832
|
-
page.node.set(pdf_lib.PDFName.of("Annots"), annots);
|
|
833
|
-
}
|
|
834
|
-
annots.push(widgetRef);
|
|
835
|
-
let acroForm = pdfDoc.catalog.lookupMaybe(pdf_lib.PDFName.of("AcroForm"), pdf_lib.PDFDict);
|
|
836
|
-
if (!acroForm) {
|
|
837
|
-
acroForm = context.obj({
|
|
838
|
-
Fields: context.obj([]),
|
|
839
|
-
SigFlags: pdf_lib.PDFNumber.of(3)
|
|
840
|
-
});
|
|
841
|
-
const acroFormRef = context.register(acroForm);
|
|
842
|
-
pdfDoc.catalog.set(pdf_lib.PDFName.of("AcroForm"), acroFormRef);
|
|
843
|
-
}
|
|
844
|
-
let fields = acroForm.lookupMaybe(pdf_lib.PDFName.of("Fields"), pdf_lib.PDFArray);
|
|
845
|
-
if (!fields) {
|
|
846
|
-
fields = context.obj([]);
|
|
847
|
-
acroForm.set(pdf_lib.PDFName.of("Fields"), fields);
|
|
848
|
-
}
|
|
849
|
-
fields.push(fieldRef);
|
|
850
|
-
return {
|
|
851
|
-
fieldRef,
|
|
852
|
-
widgetRef
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor", anchorText = "__SIG_DEBTOR_ANCHOR__") {
|
|
856
|
-
const bytes = toU8(pdf);
|
|
857
|
-
const anchor = await findAnchorPosition(bytes.slice(), anchorText);
|
|
858
|
-
const pdfDoc = await pdf_lib.PDFDocument.load(bytes);
|
|
859
|
-
const sigWidth = 240;
|
|
860
|
-
const sigHeight = 50;
|
|
861
|
-
if (anchor) {
|
|
862
|
-
const pageIndex = anchor.pageIndex;
|
|
863
|
-
const { width: pw, height: ph } = pdfDoc.getPages()[pageIndex].getSize();
|
|
864
|
-
const padX = 40;
|
|
865
|
-
const padY = 7;
|
|
866
|
-
let x = anchor.x - sigWidth / 2 + padX;
|
|
867
|
-
let y = anchor.y - sigHeight + padY;
|
|
868
|
-
const margin = 10;
|
|
869
|
-
x = Math.max(margin, Math.min(x, pw - sigWidth - margin));
|
|
870
|
-
y = Math.max(margin, Math.min(y, ph - sigHeight - margin));
|
|
871
|
-
addSignatureFieldAt(pdfDoc, anchor.pageIndex, {
|
|
872
|
-
fieldName,
|
|
873
|
-
x,
|
|
874
|
-
y,
|
|
875
|
-
width: sigWidth,
|
|
876
|
-
height: sigHeight
|
|
877
|
-
});
|
|
878
|
-
} else {
|
|
879
|
-
const pages = pdfDoc.getPages();
|
|
880
|
-
const pageIndex = pages.length - 1;
|
|
881
|
-
const { width: pageWidth } = pages[pageIndex].getSize();
|
|
882
|
-
addSignatureFieldAt(pdfDoc, pageIndex, {
|
|
883
|
-
fieldName,
|
|
884
|
-
x: (pageWidth - sigWidth) / 2,
|
|
885
|
-
y: 90,
|
|
886
|
-
width: sigWidth,
|
|
887
|
-
height: sigHeight
|
|
888
|
-
});
|
|
889
|
-
}
|
|
890
|
-
return await pdfDoc.save();
|
|
891
|
-
}
|
|
892
|
-
//#endregion
|
|
893
908
|
//#region src/nestjs-pdf.service.ts
|
|
894
909
|
let NestjsPdfService = class NestjsPdfService {
|
|
895
910
|
puppeteerService;
|
|
@@ -3762,21 +3777,6 @@ let NestjsPdfModule = _NestjsPdfModule = class NestjsPdfModule {
|
|
|
3762
3777
|
};
|
|
3763
3778
|
NestjsPdfModule = _NestjsPdfModule = __decorate([(0, _nestjs_common.Module)({})], NestjsPdfModule);
|
|
3764
3779
|
//#endregion
|
|
3765
|
-
//#region src/helpers/getRelativePath.helper.ts
|
|
3766
|
-
/**
|
|
3767
|
-
* Get the relative path to a value from the module directory.
|
|
3768
|
-
* @param moduleDir the path of the module, typically __dirname
|
|
3769
|
-
* @param relativeToModule the path to the value relative to the module directory
|
|
3770
|
-
* @returns the relative path from the current working directory to the value
|
|
3771
|
-
* @example
|
|
3772
|
-
* getRelativePathToValue(__dirname, './templates/my-template.hbs');
|
|
3773
|
-
* // returns 'context/pdf/templates/my-template.hbs' if the current working directory is '/
|
|
3774
|
-
*/
|
|
3775
|
-
function getRelativePathToValue(moduleDir, relativeToModule) {
|
|
3776
|
-
const fullTemplatePath = (0, node_path.resolve)(moduleDir, relativeToModule);
|
|
3777
|
-
return (0, node_path.relative)(process.cwd(), fullTemplatePath);
|
|
3778
|
-
}
|
|
3779
|
-
//#endregion
|
|
3780
3780
|
Object.defineProperty(exports, "EjsService", {
|
|
3781
3781
|
enumerable: true,
|
|
3782
3782
|
get: function() {
|