@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/dist/index.mjs
CHANGED
|
@@ -1,23 +1,184 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { relative, resolve } from "node:path";
|
|
2
3
|
import { Inject, Injectable, Logger, Module, Optional } from "@nestjs/common";
|
|
4
|
+
import { PDFArray, PDFDict, PDFDocument, PDFName, PDFNumber, PDFString } from "pdf-lib";
|
|
5
|
+
import { HandlebarsService } from "@gboutte/nestjs-hbs";
|
|
6
|
+
import pLimit from "p-limit";
|
|
7
|
+
import { deepmerge } from "deepmerge-ts";
|
|
3
8
|
import { existsSync, promises, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
-
import {
|
|
9
|
+
import { Browser, BrowserPlatform, canDownload, detectBrowserPlatform, getInstalledBrowsers, install, resolveBuildId } from "@puppeteer/browsers";
|
|
5
10
|
import { launch } from "puppeteer";
|
|
6
|
-
import { Browser as Browser$1, BrowserPlatform, canDownload, detectBrowserPlatform, getInstalledBrowsers, install, resolveBuildId } from "@puppeteer/browsers";
|
|
7
|
-
import { deepmerge } from "deepmerge-ts";
|
|
8
|
-
import pLimit from "p-limit";
|
|
9
|
-
import { HandlebarsService } from "@gboutte/nestjs-hbs";
|
|
10
|
-
import mjml from "mjml";
|
|
11
|
-
import { compile } from "pug";
|
|
12
11
|
import { render, renderFile } from "ejs";
|
|
13
|
-
import { configure, render as render$1, renderString } from "nunjucks";
|
|
14
12
|
import { Eta } from "eta";
|
|
13
|
+
import mjml from "mjml";
|
|
15
14
|
import mustache from "mustache";
|
|
16
|
-
import {
|
|
15
|
+
import { configure, render as render$1, renderString } from "nunjucks";
|
|
16
|
+
import { compile } from "pug";
|
|
17
17
|
//#region \0rolldown/runtime.js
|
|
18
18
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
19
19
|
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
20
20
|
//#endregion
|
|
21
|
+
//#region src/helpers/getRelativePath.helper.ts
|
|
22
|
+
/**
|
|
23
|
+
* Get the relative path to a value from the module directory.
|
|
24
|
+
* @param moduleDir the path of the module, typically __dirname
|
|
25
|
+
* @param relativeToModule the path to the value relative to the module directory
|
|
26
|
+
* @returns the relative path from the current working directory to the value
|
|
27
|
+
* @example
|
|
28
|
+
* getRelativePathToValue(__dirname, './templates/my-template.hbs');
|
|
29
|
+
* // returns 'context/pdf/templates/my-template.hbs' if the current working directory is '/
|
|
30
|
+
*/
|
|
31
|
+
function getRelativePathToValue(moduleDir, relativeToModule) {
|
|
32
|
+
const fullTemplatePath = resolve(moduleDir, relativeToModule);
|
|
33
|
+
return relative(process.cwd(), fullTemplatePath);
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/helpers/signature.helper.ts
|
|
37
|
+
let pdfjsPromise;
|
|
38
|
+
async function loadPdfjs() {
|
|
39
|
+
if (!pdfjsPromise) try {
|
|
40
|
+
pdfjsPromise = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
41
|
+
} catch (error) {
|
|
42
|
+
pdfjsPromise = void 0;
|
|
43
|
+
throw new Error([
|
|
44
|
+
"Failed to load pdfjs-dist.",
|
|
45
|
+
"If you use anchor-based signature placement in Node.js, make sure @napi-rs/canvas is installed.",
|
|
46
|
+
"Try: npm install @napi-rs/canvas",
|
|
47
|
+
"",
|
|
48
|
+
`Original error: ${error instanceof Error ? error.message : String(error)}`
|
|
49
|
+
].join("\n"), { cause: error });
|
|
50
|
+
}
|
|
51
|
+
return pdfjsPromise;
|
|
52
|
+
}
|
|
53
|
+
function toU8(input) {
|
|
54
|
+
return new Uint8Array(input);
|
|
55
|
+
}
|
|
56
|
+
async function findAnchorPosition(pdfBytes, anchorText) {
|
|
57
|
+
const pdfjsLib = await loadPdfjs();
|
|
58
|
+
const loadingTask = pdfjsLib.getDocument({ data: pdfBytes });
|
|
59
|
+
try {
|
|
60
|
+
const pdf = await loadingTask.promise;
|
|
61
|
+
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
|
62
|
+
const page = await pdf.getPage(pageNum);
|
|
63
|
+
const viewport = page.getViewport({ scale: 1 });
|
|
64
|
+
const textContent = await page.getTextContent();
|
|
65
|
+
for (const itemRaw of textContent.items) {
|
|
66
|
+
const item = itemRaw;
|
|
67
|
+
if (!item.str?.includes(anchorText)) continue;
|
|
68
|
+
const [_a, _b, _c, _d, e, f] = pdfjsLib.Util.transform(viewport.transform, item.transform);
|
|
69
|
+
const x = e;
|
|
70
|
+
const y = viewport.height - f;
|
|
71
|
+
return {
|
|
72
|
+
pageIndex: pageNum - 1,
|
|
73
|
+
x,
|
|
74
|
+
y,
|
|
75
|
+
pageWidth: viewport.width,
|
|
76
|
+
pageHeight: viewport.height
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
} finally {
|
|
82
|
+
await loadingTask.destroy();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function addSignatureFieldAt(pdfDoc, pageIndex, opts) {
|
|
86
|
+
const { fieldName, x, y, width, height } = opts;
|
|
87
|
+
const context = pdfDoc.context;
|
|
88
|
+
const page = pdfDoc.getPages()[pageIndex];
|
|
89
|
+
if (!page) throw new Error(`Page ${pageIndex} not found`);
|
|
90
|
+
const rectArray = context.obj([
|
|
91
|
+
PDFNumber.of(x),
|
|
92
|
+
PDFNumber.of(y),
|
|
93
|
+
PDFNumber.of(x + width),
|
|
94
|
+
PDFNumber.of(y + height)
|
|
95
|
+
]);
|
|
96
|
+
const widgetDict = context.obj({
|
|
97
|
+
Type: PDFName.of("Annot"),
|
|
98
|
+
Subtype: PDFName.of("Widget"),
|
|
99
|
+
Rect: rectArray,
|
|
100
|
+
F: PDFNumber.of(4),
|
|
101
|
+
P: page.ref
|
|
102
|
+
});
|
|
103
|
+
const widgetRef = context.register(widgetDict);
|
|
104
|
+
const fieldDict = context.obj({
|
|
105
|
+
FT: PDFName.of("Sig"),
|
|
106
|
+
T: PDFString.of(fieldName),
|
|
107
|
+
Ff: PDFNumber.of(0),
|
|
108
|
+
Kids: context.obj([widgetRef])
|
|
109
|
+
});
|
|
110
|
+
const fieldRef = context.register(fieldDict);
|
|
111
|
+
widgetDict.set(PDFName.of("Parent"), fieldRef);
|
|
112
|
+
let annots = page.node.lookupMaybe(PDFName.of("Annots"), PDFArray);
|
|
113
|
+
if (!annots) {
|
|
114
|
+
annots = context.obj([]);
|
|
115
|
+
page.node.set(PDFName.of("Annots"), annots);
|
|
116
|
+
}
|
|
117
|
+
annots.push(widgetRef);
|
|
118
|
+
let acroForm = pdfDoc.catalog.lookupMaybe(PDFName.of("AcroForm"), PDFDict);
|
|
119
|
+
if (!acroForm) {
|
|
120
|
+
acroForm = context.obj({
|
|
121
|
+
Fields: context.obj([]),
|
|
122
|
+
SigFlags: PDFNumber.of(3)
|
|
123
|
+
});
|
|
124
|
+
const acroFormRef = context.register(acroForm);
|
|
125
|
+
pdfDoc.catalog.set(PDFName.of("AcroForm"), acroFormRef);
|
|
126
|
+
}
|
|
127
|
+
let fields = acroForm.lookupMaybe(PDFName.of("Fields"), PDFArray);
|
|
128
|
+
if (!fields) {
|
|
129
|
+
fields = context.obj([]);
|
|
130
|
+
acroForm.set(PDFName.of("Fields"), fields);
|
|
131
|
+
}
|
|
132
|
+
fields.push(fieldRef);
|
|
133
|
+
return {
|
|
134
|
+
fieldRef,
|
|
135
|
+
widgetRef
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor", anchorText = "__SIG_DEBTOR_ANCHOR__") {
|
|
139
|
+
const bytes = toU8(pdf);
|
|
140
|
+
const anchor = await findAnchorPosition(bytes.slice(), anchorText);
|
|
141
|
+
const pdfDoc = await PDFDocument.load(bytes);
|
|
142
|
+
const sigWidth = 240;
|
|
143
|
+
const sigHeight = 50;
|
|
144
|
+
if (anchor) {
|
|
145
|
+
const pageIndex = anchor.pageIndex;
|
|
146
|
+
const { width: pw, height: ph } = pdfDoc.getPages()[pageIndex].getSize();
|
|
147
|
+
const padX = 40;
|
|
148
|
+
const padY = 7;
|
|
149
|
+
let x = anchor.x - sigWidth / 2 + padX;
|
|
150
|
+
let y = anchor.y - sigHeight + padY;
|
|
151
|
+
const margin = 10;
|
|
152
|
+
x = Math.max(margin, Math.min(x, pw - sigWidth - margin));
|
|
153
|
+
y = Math.max(margin, Math.min(y, ph - sigHeight - margin));
|
|
154
|
+
addSignatureFieldAt(pdfDoc, anchor.pageIndex, {
|
|
155
|
+
fieldName,
|
|
156
|
+
x,
|
|
157
|
+
y,
|
|
158
|
+
width: sigWidth,
|
|
159
|
+
height: sigHeight
|
|
160
|
+
});
|
|
161
|
+
} else {
|
|
162
|
+
const pages = pdfDoc.getPages();
|
|
163
|
+
const pageIndex = pages.length - 1;
|
|
164
|
+
const { width: pageWidth } = pages[pageIndex].getSize();
|
|
165
|
+
addSignatureFieldAt(pdfDoc, pageIndex, {
|
|
166
|
+
fieldName,
|
|
167
|
+
x: (pageWidth - sigWidth) / 2,
|
|
168
|
+
y: 90,
|
|
169
|
+
width: sigWidth,
|
|
170
|
+
height: sigHeight
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return await pdfDoc.save();
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
//#region src/helpers/deepMergePdfparams.ts
|
|
177
|
+
function mergePuppeteerParameters(defaults, overrides) {
|
|
178
|
+
if (!overrides) return { ...defaults };
|
|
179
|
+
return deepmerge(defaults, overrides);
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
21
182
|
//#region src/helpers/tokens.ts
|
|
22
183
|
const PDF_PARAMETERS = "PDF_PARAMETERS";
|
|
23
184
|
const HANDLEBARS_PARAMETERS = "HANDLEBARS_PARAMETERS";
|
|
@@ -207,7 +368,7 @@ let BrowserService = class BrowserService {
|
|
|
207
368
|
}
|
|
208
369
|
loadBrowser() {
|
|
209
370
|
let browser;
|
|
210
|
-
if (this.options?.browser === void 0) browser = Browser
|
|
371
|
+
if (this.options?.browser === void 0) browser = Browser.CHROMIUM;
|
|
211
372
|
else browser = this.options.browser;
|
|
212
373
|
this.browser = browser;
|
|
213
374
|
}
|
|
@@ -219,7 +380,7 @@ let BrowserService = class BrowserService {
|
|
|
219
380
|
}
|
|
220
381
|
loadBrowserTag() {
|
|
221
382
|
let versionTag;
|
|
222
|
-
if (this.options?.browserTag === void 0) if (this.browser === Browser
|
|
383
|
+
if (this.options?.browserTag === void 0) if (this.browser === Browser.CHROMIUM) versionTag = "latest";
|
|
223
384
|
else versionTag = "stable";
|
|
224
385
|
else versionTag = this.options.browserTag;
|
|
225
386
|
this.browserTag = versionTag;
|
|
@@ -249,8 +410,8 @@ let BrowserService = class BrowserService {
|
|
|
249
410
|
this.useLockedBrowser = useLockedBrowser;
|
|
250
411
|
}
|
|
251
412
|
async hasBrowserInstalled(browser, buildId) {
|
|
252
|
-
return (await getInstalledBrowsers({ cacheDir: this.cacheDir })).find((
|
|
253
|
-
return
|
|
413
|
+
return (await getInstalledBrowsers({ cacheDir: this.cacheDir })).find((insBrowser) => {
|
|
414
|
+
return insBrowser.browser === browser && insBrowser.buildId === buildId;
|
|
254
415
|
}) !== void 0;
|
|
255
416
|
}
|
|
256
417
|
async getExecutablePath() {
|
|
@@ -263,8 +424,8 @@ let BrowserService = class BrowserService {
|
|
|
263
424
|
Logger.log(`Using locked browser ${buildId}`, "NestJsPdf");
|
|
264
425
|
}
|
|
265
426
|
buildId ??= await resolveBuildId(browser, browserPlatform, versionTag);
|
|
266
|
-
const installedBrowser = (await getInstalledBrowsers({ cacheDir: this.cacheDir })).find((
|
|
267
|
-
return
|
|
427
|
+
const installedBrowser = (await getInstalledBrowsers({ cacheDir: this.cacheDir })).find((insBrowser) => {
|
|
428
|
+
return insBrowser.browser === browser && insBrowser.buildId === buildId;
|
|
268
429
|
});
|
|
269
430
|
if (installedBrowser === void 0) {
|
|
270
431
|
const newinstalledBrowser = await this.install();
|
|
@@ -311,45 +472,6 @@ BrowserService = __decorate([
|
|
|
311
472
|
__decorateMetadata("design:paramtypes", [Object])
|
|
312
473
|
], BrowserService);
|
|
313
474
|
//#endregion
|
|
314
|
-
//#region src/helpers/deepMergePdfparams.ts
|
|
315
|
-
function mergePuppeteerParameters(defaults, overrides) {
|
|
316
|
-
if (!overrides) return { ...defaults };
|
|
317
|
-
return deepmerge(defaults, overrides);
|
|
318
|
-
}
|
|
319
|
-
//#endregion
|
|
320
|
-
//#region src/puppeteer/engines/mjml/mjml.service.ts
|
|
321
|
-
let MjmlService = class MjmlService {
|
|
322
|
-
async render(template, options) {
|
|
323
|
-
const { html } = await mjml(template, options);
|
|
324
|
-
return html;
|
|
325
|
-
}
|
|
326
|
-
async renderFile(filePath, options) {
|
|
327
|
-
const template = readFileSync(filePath, "utf-8");
|
|
328
|
-
return await this.render(template, options);
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
MjmlService = __decorate([Injectable()], MjmlService);
|
|
332
|
-
//#endregion
|
|
333
|
-
//#region src/puppeteer/engines/pug/pug.service.ts
|
|
334
|
-
let PugService = class PugService {
|
|
335
|
-
render(template, data = {}, options) {
|
|
336
|
-
try {
|
|
337
|
-
return compile(template, { ...options })(data);
|
|
338
|
-
} catch (error) {
|
|
339
|
-
throw new Error(`Pug rendering failed: ${String(error)}`, { cause: error });
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
renderFile(filePath, data = {}, options) {
|
|
343
|
-
try {
|
|
344
|
-
const template = readFileSync(filePath, "utf-8");
|
|
345
|
-
return this.render(template, data, options);
|
|
346
|
-
} catch (error) {
|
|
347
|
-
throw new Error(`Pug file rendering failed: ${String(error)}`, { cause: error });
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
};
|
|
351
|
-
PugService = __decorate([Injectable()], PugService);
|
|
352
|
-
//#endregion
|
|
353
475
|
//#region src/puppeteer/engines/ejs/ejs.service.ts
|
|
354
476
|
let EjsService = class EjsService {
|
|
355
477
|
async render(template, data = {}, options) {
|
|
@@ -375,52 +497,6 @@ let EjsService = class EjsService {
|
|
|
375
497
|
};
|
|
376
498
|
EjsService = __decorate([Injectable()], EjsService);
|
|
377
499
|
//#endregion
|
|
378
|
-
//#region src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
379
|
-
let NunjucksService = class NunjucksService {
|
|
380
|
-
constructor() {
|
|
381
|
-
configure({
|
|
382
|
-
noCache: true,
|
|
383
|
-
trimBlocks: true,
|
|
384
|
-
lstripBlocks: true
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
render(template, data = {}, options) {
|
|
388
|
-
try {
|
|
389
|
-
if (options) {
|
|
390
|
-
const configOptions = {
|
|
391
|
-
noCache: options.noCache ?? true,
|
|
392
|
-
watch: options.watch ?? false,
|
|
393
|
-
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
394
|
-
trimBlocks: options.trimBlocks ?? true,
|
|
395
|
-
lstripBlocks: options.lstripBlocks ?? true
|
|
396
|
-
};
|
|
397
|
-
configure(configOptions);
|
|
398
|
-
}
|
|
399
|
-
return renderString(template, data);
|
|
400
|
-
} catch (error) {
|
|
401
|
-
throw new Error(`Nunjucks rendering failed: ${String(error)}`, { cause: error });
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
renderFile(filePath, data = {}, options) {
|
|
405
|
-
try {
|
|
406
|
-
if (options) {
|
|
407
|
-
const configOptions = {
|
|
408
|
-
noCache: options.noCache ?? true,
|
|
409
|
-
watch: options.watch ?? false,
|
|
410
|
-
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
411
|
-
trimBlocks: options.trimBlocks ?? true,
|
|
412
|
-
lstripBlocks: options.lstripBlocks ?? true
|
|
413
|
-
};
|
|
414
|
-
configure(configOptions);
|
|
415
|
-
}
|
|
416
|
-
return render$1(filePath, data);
|
|
417
|
-
} catch (error) {
|
|
418
|
-
throw new Error(`Nunjucks file rendering failed: ${String(error)}`, { cause: error });
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
NunjucksService = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [])], NunjucksService);
|
|
423
|
-
//#endregion
|
|
424
500
|
//#region src/puppeteer/engines/eta/eta.service.ts
|
|
425
501
|
let EtaService = class EtaService {
|
|
426
502
|
eta;
|
|
@@ -490,6 +566,19 @@ let EtaService = class EtaService {
|
|
|
490
566
|
};
|
|
491
567
|
EtaService = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [])], EtaService);
|
|
492
568
|
//#endregion
|
|
569
|
+
//#region src/puppeteer/engines/mjml/mjml.service.ts
|
|
570
|
+
let MjmlService = class MjmlService {
|
|
571
|
+
async render(template, options) {
|
|
572
|
+
const { html } = await mjml(template, options);
|
|
573
|
+
return html;
|
|
574
|
+
}
|
|
575
|
+
async renderFile(filePath, options) {
|
|
576
|
+
const template = readFileSync(filePath, "utf-8");
|
|
577
|
+
return await this.render(template, options);
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
MjmlService = __decorate([Injectable()], MjmlService);
|
|
581
|
+
//#endregion
|
|
493
582
|
//#region src/puppeteer/engines/mustache/mustache.service.ts
|
|
494
583
|
let MustacheService = class MustacheService {
|
|
495
584
|
templateCache = /* @__PURE__ */ new Map();
|
|
@@ -548,6 +637,72 @@ let MustacheService = class MustacheService {
|
|
|
548
637
|
};
|
|
549
638
|
MustacheService = __decorate([Injectable()], MustacheService);
|
|
550
639
|
//#endregion
|
|
640
|
+
//#region src/puppeteer/engines/nunjucks/nunjucks.service.ts
|
|
641
|
+
let NunjucksService = class NunjucksService {
|
|
642
|
+
constructor() {
|
|
643
|
+
configure({
|
|
644
|
+
noCache: true,
|
|
645
|
+
trimBlocks: true,
|
|
646
|
+
lstripBlocks: true
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
render(template, data = {}, options) {
|
|
650
|
+
try {
|
|
651
|
+
if (options) {
|
|
652
|
+
const configOptions = {
|
|
653
|
+
noCache: options.noCache ?? true,
|
|
654
|
+
watch: options.watch ?? false,
|
|
655
|
+
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
656
|
+
trimBlocks: options.trimBlocks ?? true,
|
|
657
|
+
lstripBlocks: options.lstripBlocks ?? true
|
|
658
|
+
};
|
|
659
|
+
configure(configOptions);
|
|
660
|
+
}
|
|
661
|
+
return renderString(template, data);
|
|
662
|
+
} catch (error) {
|
|
663
|
+
throw new Error(`Nunjucks rendering failed: ${String(error)}`, { cause: error });
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
renderFile(filePath, data = {}, options) {
|
|
667
|
+
try {
|
|
668
|
+
if (options) {
|
|
669
|
+
const configOptions = {
|
|
670
|
+
noCache: options.noCache ?? true,
|
|
671
|
+
watch: options.watch ?? false,
|
|
672
|
+
throwOnUndefined: options.throwOnUndefined ?? false,
|
|
673
|
+
trimBlocks: options.trimBlocks ?? true,
|
|
674
|
+
lstripBlocks: options.lstripBlocks ?? true
|
|
675
|
+
};
|
|
676
|
+
configure(configOptions);
|
|
677
|
+
}
|
|
678
|
+
return render$1(filePath, data);
|
|
679
|
+
} catch (error) {
|
|
680
|
+
throw new Error(`Nunjucks file rendering failed: ${String(error)}`, { cause: error });
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
NunjucksService = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [])], NunjucksService);
|
|
685
|
+
//#endregion
|
|
686
|
+
//#region src/puppeteer/engines/pug/pug.service.ts
|
|
687
|
+
let PugService = class PugService {
|
|
688
|
+
render(template, data = {}, options) {
|
|
689
|
+
try {
|
|
690
|
+
return compile(template, { ...options })(data);
|
|
691
|
+
} catch (error) {
|
|
692
|
+
throw new Error(`Pug rendering failed: ${String(error)}`, { cause: error });
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
renderFile(filePath, data = {}, options) {
|
|
696
|
+
try {
|
|
697
|
+
const template = readFileSync(filePath, "utf-8");
|
|
698
|
+
return this.render(template, data, options);
|
|
699
|
+
} catch (error) {
|
|
700
|
+
throw new Error(`Pug file rendering failed: ${String(error)}`, { cause: error });
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
PugService = __decorate([Injectable()], PugService);
|
|
705
|
+
//#endregion
|
|
551
706
|
//#region src/puppeteer/libs/requireService.utils.ts
|
|
552
707
|
function requireService(service, name) {
|
|
553
708
|
if (!service) throw new Error(`${name} service is not available. If the problem persists, open an issue in the repo.`);
|
|
@@ -728,146 +883,6 @@ PuppeteerService = __decorate([
|
|
|
728
883
|
])
|
|
729
884
|
], PuppeteerService);
|
|
730
885
|
//#endregion
|
|
731
|
-
//#region src/helpers/signature.helper.ts
|
|
732
|
-
let pdfjsPromise;
|
|
733
|
-
async function loadPdfjs() {
|
|
734
|
-
if (!pdfjsPromise) try {
|
|
735
|
-
pdfjsPromise = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
736
|
-
} catch (error) {
|
|
737
|
-
pdfjsPromise = void 0;
|
|
738
|
-
throw new Error([
|
|
739
|
-
"Failed to load pdfjs-dist.",
|
|
740
|
-
"If you use anchor-based signature placement in Node.js, make sure @napi-rs/canvas is installed.",
|
|
741
|
-
"Try: npm install @napi-rs/canvas",
|
|
742
|
-
"",
|
|
743
|
-
`Original error: ${error instanceof Error ? error.message : String(error)}`
|
|
744
|
-
].join("\n"), { cause: error });
|
|
745
|
-
}
|
|
746
|
-
return pdfjsPromise;
|
|
747
|
-
}
|
|
748
|
-
function toU8(input) {
|
|
749
|
-
return new Uint8Array(input);
|
|
750
|
-
}
|
|
751
|
-
async function findAnchorPosition(pdfBytes, anchorText) {
|
|
752
|
-
const pdfjsLib = await loadPdfjs();
|
|
753
|
-
const loadingTask = pdfjsLib.getDocument({ data: pdfBytes });
|
|
754
|
-
try {
|
|
755
|
-
const pdf = await loadingTask.promise;
|
|
756
|
-
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
|
757
|
-
const page = await pdf.getPage(pageNum);
|
|
758
|
-
const viewport = page.getViewport({ scale: 1 });
|
|
759
|
-
const textContent = await page.getTextContent();
|
|
760
|
-
for (const itemRaw of textContent.items) {
|
|
761
|
-
const item = itemRaw;
|
|
762
|
-
if (!item.str?.includes(anchorText)) continue;
|
|
763
|
-
const [_a, _b, _c, _d, e, f] = pdfjsLib.Util.transform(viewport.transform, item.transform);
|
|
764
|
-
const x = e;
|
|
765
|
-
const y = viewport.height - f;
|
|
766
|
-
return {
|
|
767
|
-
pageIndex: pageNum - 1,
|
|
768
|
-
x,
|
|
769
|
-
y,
|
|
770
|
-
pageWidth: viewport.width,
|
|
771
|
-
pageHeight: viewport.height
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
return null;
|
|
776
|
-
} finally {
|
|
777
|
-
await loadingTask.destroy();
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
function addSignatureFieldAt(pdfDoc, pageIndex, opts) {
|
|
781
|
-
const { fieldName, x, y, width, height } = opts;
|
|
782
|
-
const context = pdfDoc.context;
|
|
783
|
-
const page = pdfDoc.getPages()[pageIndex];
|
|
784
|
-
if (!page) throw new Error(`Page ${pageIndex} not found`);
|
|
785
|
-
const rectArray = context.obj([
|
|
786
|
-
PDFNumber.of(x),
|
|
787
|
-
PDFNumber.of(y),
|
|
788
|
-
PDFNumber.of(x + width),
|
|
789
|
-
PDFNumber.of(y + height)
|
|
790
|
-
]);
|
|
791
|
-
const widgetDict = context.obj({
|
|
792
|
-
Type: PDFName.of("Annot"),
|
|
793
|
-
Subtype: PDFName.of("Widget"),
|
|
794
|
-
Rect: rectArray,
|
|
795
|
-
F: PDFNumber.of(4),
|
|
796
|
-
P: page.ref
|
|
797
|
-
});
|
|
798
|
-
const widgetRef = context.register(widgetDict);
|
|
799
|
-
const fieldDict = context.obj({
|
|
800
|
-
FT: PDFName.of("Sig"),
|
|
801
|
-
T: PDFString.of(fieldName),
|
|
802
|
-
Ff: PDFNumber.of(0),
|
|
803
|
-
Kids: context.obj([widgetRef])
|
|
804
|
-
});
|
|
805
|
-
const fieldRef = context.register(fieldDict);
|
|
806
|
-
widgetDict.set(PDFName.of("Parent"), fieldRef);
|
|
807
|
-
let annots = page.node.lookupMaybe(PDFName.of("Annots"), PDFArray);
|
|
808
|
-
if (!annots) {
|
|
809
|
-
annots = context.obj([]);
|
|
810
|
-
page.node.set(PDFName.of("Annots"), annots);
|
|
811
|
-
}
|
|
812
|
-
annots.push(widgetRef);
|
|
813
|
-
let acroForm = pdfDoc.catalog.lookupMaybe(PDFName.of("AcroForm"), PDFDict);
|
|
814
|
-
if (!acroForm) {
|
|
815
|
-
acroForm = context.obj({
|
|
816
|
-
Fields: context.obj([]),
|
|
817
|
-
SigFlags: PDFNumber.of(3)
|
|
818
|
-
});
|
|
819
|
-
const acroFormRef = context.register(acroForm);
|
|
820
|
-
pdfDoc.catalog.set(PDFName.of("AcroForm"), acroFormRef);
|
|
821
|
-
}
|
|
822
|
-
let fields = acroForm.lookupMaybe(PDFName.of("Fields"), PDFArray);
|
|
823
|
-
if (!fields) {
|
|
824
|
-
fields = context.obj([]);
|
|
825
|
-
acroForm.set(PDFName.of("Fields"), fields);
|
|
826
|
-
}
|
|
827
|
-
fields.push(fieldRef);
|
|
828
|
-
return {
|
|
829
|
-
fieldRef,
|
|
830
|
-
widgetRef
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor", anchorText = "__SIG_DEBTOR_ANCHOR__") {
|
|
834
|
-
const bytes = toU8(pdf);
|
|
835
|
-
const anchor = await findAnchorPosition(bytes.slice(), anchorText);
|
|
836
|
-
const pdfDoc = await PDFDocument.load(bytes);
|
|
837
|
-
const sigWidth = 240;
|
|
838
|
-
const sigHeight = 50;
|
|
839
|
-
if (anchor) {
|
|
840
|
-
const pageIndex = anchor.pageIndex;
|
|
841
|
-
const { width: pw, height: ph } = pdfDoc.getPages()[pageIndex].getSize();
|
|
842
|
-
const padX = 40;
|
|
843
|
-
const padY = 7;
|
|
844
|
-
let x = anchor.x - sigWidth / 2 + padX;
|
|
845
|
-
let y = anchor.y - sigHeight + padY;
|
|
846
|
-
const margin = 10;
|
|
847
|
-
x = Math.max(margin, Math.min(x, pw - sigWidth - margin));
|
|
848
|
-
y = Math.max(margin, Math.min(y, ph - sigHeight - margin));
|
|
849
|
-
addSignatureFieldAt(pdfDoc, anchor.pageIndex, {
|
|
850
|
-
fieldName,
|
|
851
|
-
x,
|
|
852
|
-
y,
|
|
853
|
-
width: sigWidth,
|
|
854
|
-
height: sigHeight
|
|
855
|
-
});
|
|
856
|
-
} else {
|
|
857
|
-
const pages = pdfDoc.getPages();
|
|
858
|
-
const pageIndex = pages.length - 1;
|
|
859
|
-
const { width: pageWidth } = pages[pageIndex].getSize();
|
|
860
|
-
addSignatureFieldAt(pdfDoc, pageIndex, {
|
|
861
|
-
fieldName,
|
|
862
|
-
x: (pageWidth - sigWidth) / 2,
|
|
863
|
-
y: 90,
|
|
864
|
-
width: sigWidth,
|
|
865
|
-
height: sigHeight
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
return await pdfDoc.save();
|
|
869
|
-
}
|
|
870
|
-
//#endregion
|
|
871
886
|
//#region src/nestjs-pdf.service.ts
|
|
872
887
|
let NestjsPdfService = class NestjsPdfService {
|
|
873
888
|
puppeteerService;
|
|
@@ -3740,21 +3755,6 @@ let NestjsPdfModule = _NestjsPdfModule = class NestjsPdfModule {
|
|
|
3740
3755
|
};
|
|
3741
3756
|
NestjsPdfModule = _NestjsPdfModule = __decorate([Module({})], NestjsPdfModule);
|
|
3742
3757
|
//#endregion
|
|
3743
|
-
//#region src/helpers/getRelativePath.helper.ts
|
|
3744
|
-
/**
|
|
3745
|
-
* Get the relative path to a value from the module directory.
|
|
3746
|
-
* @param moduleDir the path of the module, typically __dirname
|
|
3747
|
-
* @param relativeToModule the path to the value relative to the module directory
|
|
3748
|
-
* @returns the relative path from the current working directory to the value
|
|
3749
|
-
* @example
|
|
3750
|
-
* getRelativePathToValue(__dirname, './templates/my-template.hbs');
|
|
3751
|
-
* // returns 'context/pdf/templates/my-template.hbs' if the current working directory is '/
|
|
3752
|
-
*/
|
|
3753
|
-
function getRelativePathToValue(moduleDir, relativeToModule) {
|
|
3754
|
-
const fullTemplatePath = resolve(moduleDir, relativeToModule);
|
|
3755
|
-
return relative(process.cwd(), fullTemplatePath);
|
|
3756
|
-
}
|
|
3757
|
-
//#endregion
|
|
3758
3758
|
export { EjsService, EtaService, MjmlService, MustacheService, NestjsPdfModule, NestjsPdfService, NunjucksService, PugService, PuppeteerModule, PuppeteerService, getRelativePathToValue };
|
|
3759
3759
|
|
|
3760
3760
|
//# sourceMappingURL=index.mjs.map
|