@shad0wz7/nestjs-pdf 2.5.2 → 2.5.4

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # nestjs-pdf
2
2
 
3
+ > **⚠️ Maintenance branch — NestJS 11 / CommonJS (v2.x).**
4
+ > This is the `v2` line: CommonJS-only, built for **NestJS 11**. It's kept for
5
+ > maintenance/security fixes only — no new features land here.
6
+ >
7
+ > Active development has moved to **v3**, on the `main` branch: ESM-first with
8
+ > a dual CJS/ESM build, and requires **NestJS 12+**. See its
9
+ > [README](https://github.com/ShadowZ11/nestjs-pdf/blob/main/README.md) for
10
+ > details, and pin this line explicitly if you need it:
11
+ >
12
+ > ```bash
13
+ > npm install @shad0wz7/nestjs-pdf@^2
14
+ > ```
15
+
3
16
  [![npm version](https://img.shields.io/npm/v/%40shad0wz7%2Fnestjs-pdf?label=npm%20version)](https://www.npmjs.com/package/%40shad0wz7%2Fnestjs-pdf)
4
17
  [![NPM License](https://img.shields.io/npm/l/%40shad0wz7%2Fnestjs-pdf)](https://github.com/ShadowZ11/nestjs-pdf?tab=MIT-1-ov-file)
5
18
  [![npm downloads](https://img.shields.io/npm/dm/%40shad0wz7%2Fnestjs-pdf?label=npm%20downloads)](https://www.npmjs.com/package/%40shad0wz7%2Fnestjs-pdf)
@@ -7,7 +20,6 @@
7
20
  [![codecov](https://codecov.io/github/ShadowZ11/nestjs-pdf/graph/badge.svg?token=K0MNB1ZKYK)](https://codecov.io/github/ShadowZ11/nestjs-pdf)
8
21
  [![TypeScript](https://img.shields.io/badge/TypeScript-6.0.3-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
9
22
 
10
-
11
23
  A NestJS library to generate and manipulate PDFs using Puppeteer and multiple template engines, including Handlebars, EJS, Pug, MJML, Nunjucks, Eta and Mustache.
12
24
 
13
25
  Main features:
@@ -117,9 +129,8 @@ If the anchor is not found, the signature field will be added at a default posit
117
129
 
118
130
  The library exposes Puppeteer options via the `PuppeteerParameters` interface (see `src/puppeteer/puppeteer-parameters.interface.ts`). You can configure:
119
131
 
120
-
121
132
  | | Description |
122
- |-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
133
+ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
123
134
  | `pdfOptions` | The pdf options can be found on: https://pptr.dev/api/puppeteer.pdfoptions. Native Puppeteer options for `page.pdf` |
124
135
  | `hbsOptions` | The handlebars can be found on [@gboutte/nestjs-hbs](https://github.com/gboutte/nestjs-hbs) as it use a peer dependency and not handlebars directly |
125
136
  | `ejsOptions` | The ejs options can be found on [EJS documentation](https://ejs.co/#options) |
@@ -139,6 +150,7 @@ The library exposes Puppeteer options via the `PuppeteerParameters` interface (s
139
150
  | `executablePath` | The path to the browser executable to use. If not specified, Puppeteer will install Chromium in cache dir. (useLockedBrowser is useless with this param specified) |
140
151
 
141
152
  these are the default extra arguments passed to Puppeteer:
153
+
142
154
  ```ts
143
155
  [
144
156
  '--autoplay-policy=user-gesture-required',
package/dist/index.cjs CHANGED
@@ -63,12 +63,14 @@ async function loadPdfjs() {
63
63
  pdfjsPromise = await import("pdfjs-dist/legacy/build/pdf.mjs");
64
64
  } catch (error) {
65
65
  pdfjsPromise = void 0;
66
+ /* v8 ignore next -- import() rejections are always Error instances in practice */
67
+ const reason = error instanceof Error ? error.message : String(error);
66
68
  throw new Error([
67
69
  "Failed to load pdfjs-dist.",
68
70
  "If you use anchor-based signature placement in Node.js, make sure @napi-rs/canvas is installed.",
69
71
  "Try: npm install @napi-rs/canvas",
70
72
  "",
71
- `Original error: ${error instanceof Error ? error.message : String(error)}`
73
+ `Original error: ${reason}`
72
74
  ].join("\n"), { cause: error });
73
75
  }
74
76
  return pdfjsPromise;
@@ -109,7 +111,6 @@ function addSignatureFieldAt(pdfDoc, pageIndex, opts) {
109
111
  const { fieldName, x, y, width, height } = opts;
110
112
  const context = pdfDoc.context;
111
113
  const page = pdfDoc.getPages()[pageIndex];
112
- if (!page) throw new Error(`Page ${pageIndex} not found`);
113
114
  const rectArray = context.obj([
114
115
  pdf_lib.PDFNumber.of(x),
115
116
  pdf_lib.PDFNumber.of(y),
@@ -166,7 +167,9 @@ async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor",
166
167
  const sigHeight = 50;
167
168
  if (anchor) {
168
169
  const pageIndex = anchor.pageIndex;
169
- const { width: pw, height: ph } = pdfDoc.getPages()[pageIndex].getSize();
170
+ const page = pdfDoc.getPages()[pageIndex];
171
+ if (!page) throw new Error(`Page ${pageIndex} not found`);
172
+ const { width: pw, height: ph } = page.getSize();
170
173
  const padX = 40;
171
174
  const padY = 7;
172
175
  let x = anchor.x - sigWidth / 2 + padX;
@@ -184,7 +187,10 @@ async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor",
184
187
  } else {
185
188
  const pages = pdfDoc.getPages();
186
189
  const pageIndex = pages.length - 1;
187
- const { width: pageWidth } = pages[pageIndex].getSize();
190
+ const page = pages.at(-1);
191
+ /* v8 ignore next -- pdf-lib always produces at least one page on save/load; only a hand-crafted, malformed PDF could hit this */
192
+ if (!page) throw new Error(`Page ${pageIndex} not found`);
193
+ const { width: pageWidth } = page.getSize();
188
194
  addSignatureFieldAt(pdfDoc, pageIndex, {
189
195
  fieldName,
190
196
  x: (pageWidth - sigWidth) / 2,
@@ -256,19 +262,23 @@ let BrowserService = class BrowserService {
256
262
  totalJobs = 0;
257
263
  recycleRequested = false;
258
264
  recycling = false;
265
+ shuttingDown = false;
266
+ /** Max time to wait for in-flight PDF jobs to finish before closing the browser on shutdown. */
267
+ shutdownDrainTimeoutMs = 15e3;
259
268
  browserTag;
260
269
  useLockedBrowser;
261
270
  buildId;
262
271
  constructor(pdfParams) {
263
272
  this.cacheDir = (0, node_path.resolve)(".cache/puppeteer-browser");
264
273
  this.options = pdfParams;
265
- if (pdfParams.cleanupBrowserCacheOnExit) this.registerCleanupHooks();
266
274
  this.loadBuildId();
267
275
  this.loadBrowser();
268
276
  this.loadBrowserTag();
269
277
  this.loadUseLockedBrowser();
270
278
  }
271
279
  async onModuleDestroy() {
280
+ this.shuttingDown = true;
281
+ await this.waitForIdle(this.shutdownDrainTimeoutMs);
272
282
  if (this._browserInstance?.connected) try {
273
283
  await this._browserInstance.close();
274
284
  } catch (error) {
@@ -276,6 +286,12 @@ let BrowserService = class BrowserService {
276
286
  }
277
287
  await this.cleanupCacheBestEffort();
278
288
  }
289
+ /** Wait until no PDF job is in flight, or until the timeout elapses. */
290
+ async waitForIdle(timeoutMs) {
291
+ const start = Date.now();
292
+ while (this.activeJobs > 0 && Date.now() - start < timeoutMs) await sleep(50);
293
+ if (this.activeJobs > 0) _nestjs_common.Logger.warn(`Shutdown: ${this.activeJobs} PDF job(s) still running after ${timeoutMs}ms, closing the browser anyway`);
294
+ }
279
295
  async getBrowserInstance(args, headless, executablePathBin) {
280
296
  if (!this._browserInstance?.connected) this._browserInstance = await this.launchBrowser(args, headless, executablePathBin);
281
297
  return this._browserInstance;
@@ -292,6 +308,7 @@ let BrowserService = class BrowserService {
292
308
  }
293
309
  }
294
310
  markJobStarted() {
311
+ if (this.shuttingDown) throw new Error("nestjs-pdf is shutting down, refusing new PDF jobs");
295
312
  this.activeJobs += 1;
296
313
  this.totalJobs += 1;
297
314
  if (this.totalJobs >= 200) this.recycleRequested = true;
@@ -323,7 +340,7 @@ let BrowserService = class BrowserService {
323
340
  const dir = this.cacheDir;
324
341
  try {
325
342
  if (!(0, node_fs.existsSync)(dir)) return;
326
- logger.log(`Cleanup puppeteer cache on signal: ${dir}`);
343
+ logger.log(`Cleanup puppeteer cache: ${dir}`);
327
344
  await rmWithRetries(dir, 6);
328
345
  if ((0, node_fs.existsSync)(dir)) {
329
346
  await sleep(100);
@@ -372,23 +389,6 @@ let BrowserService = class BrowserService {
372
389
  }
373
390
  return null;
374
391
  }
375
- registerCleanupHooks() {
376
- const cleanup = async (signal) => {
377
- try {
378
- _nestjs_common.Logger.log(`Received ${signal}, cleaning up puppeteer cache...`, "NestJsPdf");
379
- await this.cleanupCacheBestEffort();
380
- process.exit(0);
381
- } catch {
382
- process.exit(1);
383
- }
384
- };
385
- const cleanupHandler = (signal) => {
386
- cleanup(signal);
387
- };
388
- process.once("SIGTERM", cleanupHandler);
389
- process.once("SIGINT", cleanupHandler);
390
- process.once("exit", cleanupHandler);
391
- }
392
392
  loadBrowser() {
393
393
  let browser;
394
394
  if (this.options?.browser === void 0) browser = _puppeteer_browsers.Browser.CHROMIUM;
package/dist/index.d.cts CHANGED
@@ -39,11 +39,16 @@ declare class BrowserService implements OnModuleDestroy {
39
39
  totalJobs: number;
40
40
  private recycleRequested;
41
41
  private recycling;
42
+ private shuttingDown;
43
+ /** Max time to wait for in-flight PDF jobs to finish before closing the browser on shutdown. */
44
+ shutdownDrainTimeoutMs: number;
42
45
  private browserTag;
43
46
  private useLockedBrowser;
44
47
  private buildId;
45
48
  constructor(pdfParams: PuppeteerParameters);
46
49
  onModuleDestroy(): Promise<void>;
50
+ /** Wait until no PDF job is in flight, or until the timeout elapses. */
51
+ private waitForIdle;
47
52
  getBrowserInstance(args: Array<string>, headless: boolean | 'shell' | undefined, executablePathBin: string | undefined): Promise<Browser$1>;
48
53
  createContext(args: Array<string>, headless: Headless, executablePath?: string): Promise<BrowserContext>;
49
54
  markJobStarted(): void;
@@ -51,7 +56,6 @@ declare class BrowserService implements OnModuleDestroy {
51
56
  recycleBrowserIfNeeded(): Promise<void>;
52
57
  private cleanupCacheBestEffort;
53
58
  install(lock?: boolean): Promise<import("@puppeteer/browsers", { with: { "resolution-mode": "import" } }).InstalledBrowser | null | undefined>;
54
- private registerCleanupHooks;
55
59
  private loadBrowser;
56
60
  setBrowser(browser: Browser): void;
57
61
  getBrowser(): Browser;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/helpers/getRelativePath.helper.ts","../src/puppeteer/browser/browser.service.ts","../src/puppeteer/engines/ejs/ejs.service.ts","../src/puppeteer/engines/eta/eta.service.ts","../src/puppeteer/engines/mustache/mustache.service.ts","../src/puppeteer/engines/nunjucks/nunjucks.service.ts","../src/puppeteer/engines/pug/pug.service.ts","../src/puppeteer/puppeteer-parameters.interface.ts","../src/nestjs-pdf.module.ts","../src/puppeteer/engines/mjml/mjml.service.ts","../src/puppeteer/puppeteer.service.ts","../src/nestjs-pdf.service.ts","../src/puppeteer/puppeteer.module.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/helpers/getRelativePath.helper.ts","../src/puppeteer/browser/browser.service.ts","../src/puppeteer/engines/ejs/ejs.service.ts","../src/puppeteer/engines/eta/eta.service.ts","../src/puppeteer/engines/mustache/mustache.service.ts","../src/puppeteer/engines/nunjucks/nunjucks.service.ts","../src/puppeteer/engines/pug/pug.service.ts","../src/puppeteer/puppeteer-parameters.interface.ts","../src/nestjs-pdf.module.ts","../src/puppeteer/engines/mjml/mjml.service.ts","../src/puppeteer/puppeteer.service.ts","../src/nestjs-pdf.service.ts","../src/puppeteer/puppeteer.module.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -39,11 +39,16 @@ declare class BrowserService implements OnModuleDestroy {
39
39
  totalJobs: number;
40
40
  private recycleRequested;
41
41
  private recycling;
42
+ private shuttingDown;
43
+ /** Max time to wait for in-flight PDF jobs to finish before closing the browser on shutdown. */
44
+ shutdownDrainTimeoutMs: number;
42
45
  private browserTag;
43
46
  private useLockedBrowser;
44
47
  private buildId;
45
48
  constructor(pdfParams: PuppeteerParameters);
46
49
  onModuleDestroy(): Promise<void>;
50
+ /** Wait until no PDF job is in flight, or until the timeout elapses. */
51
+ private waitForIdle;
47
52
  getBrowserInstance(args: Array<string>, headless: boolean | 'shell' | undefined, executablePathBin: string | undefined): Promise<Browser$1>;
48
53
  createContext(args: Array<string>, headless: Headless, executablePath?: string): Promise<BrowserContext>;
49
54
  markJobStarted(): void;
@@ -51,7 +56,6 @@ declare class BrowserService implements OnModuleDestroy {
51
56
  recycleBrowserIfNeeded(): Promise<void>;
52
57
  private cleanupCacheBestEffort;
53
58
  install(lock?: boolean): Promise<import("@puppeteer/browsers", { with: { "resolution-mode": "import" } }).InstalledBrowser | null | undefined>;
54
- private registerCleanupHooks;
55
59
  private loadBrowser;
56
60
  setBrowser(browser: Browser): void;
57
61
  getBrowser(): Browser;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/helpers/getRelativePath.helper.ts","../src/puppeteer/browser/browser.service.ts","../src/puppeteer/engines/ejs/ejs.service.ts","../src/puppeteer/engines/eta/eta.service.ts","../src/puppeteer/engines/mustache/mustache.service.ts","../src/puppeteer/engines/nunjucks/nunjucks.service.ts","../src/puppeteer/engines/pug/pug.service.ts","../src/puppeteer/puppeteer-parameters.interface.ts","../src/nestjs-pdf.module.ts","../src/puppeteer/engines/mjml/mjml.service.ts","../src/puppeteer/puppeteer.service.ts","../src/nestjs-pdf.service.ts","../src/puppeteer/puppeteer.module.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/helpers/getRelativePath.helper.ts","../src/puppeteer/browser/browser.service.ts","../src/puppeteer/engines/ejs/ejs.service.ts","../src/puppeteer/engines/eta/eta.service.ts","../src/puppeteer/engines/mustache/mustache.service.ts","../src/puppeteer/engines/nunjucks/nunjucks.service.ts","../src/puppeteer/engines/pug/pug.service.ts","../src/puppeteer/puppeteer-parameters.interface.ts","../src/nestjs-pdf.module.ts","../src/puppeteer/engines/mjml/mjml.service.ts","../src/puppeteer/puppeteer.service.ts","../src/nestjs-pdf.service.ts","../src/puppeteer/puppeteer.module.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -40,12 +40,14 @@ async function loadPdfjs() {
40
40
  pdfjsPromise = await import("pdfjs-dist/legacy/build/pdf.mjs");
41
41
  } catch (error) {
42
42
  pdfjsPromise = void 0;
43
+ /* v8 ignore next -- import() rejections are always Error instances in practice */
44
+ const reason = error instanceof Error ? error.message : String(error);
43
45
  throw new Error([
44
46
  "Failed to load pdfjs-dist.",
45
47
  "If you use anchor-based signature placement in Node.js, make sure @napi-rs/canvas is installed.",
46
48
  "Try: npm install @napi-rs/canvas",
47
49
  "",
48
- `Original error: ${error instanceof Error ? error.message : String(error)}`
50
+ `Original error: ${reason}`
49
51
  ].join("\n"), { cause: error });
50
52
  }
51
53
  return pdfjsPromise;
@@ -86,7 +88,6 @@ function addSignatureFieldAt(pdfDoc, pageIndex, opts) {
86
88
  const { fieldName, x, y, width, height } = opts;
87
89
  const context = pdfDoc.context;
88
90
  const page = pdfDoc.getPages()[pageIndex];
89
- if (!page) throw new Error(`Page ${pageIndex} not found`);
90
91
  const rectArray = context.obj([
91
92
  PDFNumber.of(x),
92
93
  PDFNumber.of(y),
@@ -143,7 +144,9 @@ async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor",
143
144
  const sigHeight = 50;
144
145
  if (anchor) {
145
146
  const pageIndex = anchor.pageIndex;
146
- const { width: pw, height: ph } = pdfDoc.getPages()[pageIndex].getSize();
147
+ const page = pdfDoc.getPages()[pageIndex];
148
+ if (!page) throw new Error(`Page ${pageIndex} not found`);
149
+ const { width: pw, height: ph } = page.getSize();
147
150
  const padX = 40;
148
151
  const padY = 7;
149
152
  let x = anchor.x - sigWidth / 2 + padX;
@@ -161,7 +164,10 @@ async function addSignatureFieldUsingAnchor(pdf, fieldName = "SignatureDebtor",
161
164
  } else {
162
165
  const pages = pdfDoc.getPages();
163
166
  const pageIndex = pages.length - 1;
164
- const { width: pageWidth } = pages[pageIndex].getSize();
167
+ const page = pages.at(-1);
168
+ /* v8 ignore next -- pdf-lib always produces at least one page on save/load; only a hand-crafted, malformed PDF could hit this */
169
+ if (!page) throw new Error(`Page ${pageIndex} not found`);
170
+ const { width: pageWidth } = page.getSize();
165
171
  addSignatureFieldAt(pdfDoc, pageIndex, {
166
172
  fieldName,
167
173
  x: (pageWidth - sigWidth) / 2,
@@ -233,19 +239,23 @@ let BrowserService = class BrowserService {
233
239
  totalJobs = 0;
234
240
  recycleRequested = false;
235
241
  recycling = false;
242
+ shuttingDown = false;
243
+ /** Max time to wait for in-flight PDF jobs to finish before closing the browser on shutdown. */
244
+ shutdownDrainTimeoutMs = 15e3;
236
245
  browserTag;
237
246
  useLockedBrowser;
238
247
  buildId;
239
248
  constructor(pdfParams) {
240
249
  this.cacheDir = resolve(".cache/puppeteer-browser");
241
250
  this.options = pdfParams;
242
- if (pdfParams.cleanupBrowserCacheOnExit) this.registerCleanupHooks();
243
251
  this.loadBuildId();
244
252
  this.loadBrowser();
245
253
  this.loadBrowserTag();
246
254
  this.loadUseLockedBrowser();
247
255
  }
248
256
  async onModuleDestroy() {
257
+ this.shuttingDown = true;
258
+ await this.waitForIdle(this.shutdownDrainTimeoutMs);
249
259
  if (this._browserInstance?.connected) try {
250
260
  await this._browserInstance.close();
251
261
  } catch (error) {
@@ -253,6 +263,12 @@ let BrowserService = class BrowserService {
253
263
  }
254
264
  await this.cleanupCacheBestEffort();
255
265
  }
266
+ /** Wait until no PDF job is in flight, or until the timeout elapses. */
267
+ async waitForIdle(timeoutMs) {
268
+ const start = Date.now();
269
+ while (this.activeJobs > 0 && Date.now() - start < timeoutMs) await sleep(50);
270
+ if (this.activeJobs > 0) Logger.warn(`Shutdown: ${this.activeJobs} PDF job(s) still running after ${timeoutMs}ms, closing the browser anyway`);
271
+ }
256
272
  async getBrowserInstance(args, headless, executablePathBin) {
257
273
  if (!this._browserInstance?.connected) this._browserInstance = await this.launchBrowser(args, headless, executablePathBin);
258
274
  return this._browserInstance;
@@ -269,6 +285,7 @@ let BrowserService = class BrowserService {
269
285
  }
270
286
  }
271
287
  markJobStarted() {
288
+ if (this.shuttingDown) throw new Error("nestjs-pdf is shutting down, refusing new PDF jobs");
272
289
  this.activeJobs += 1;
273
290
  this.totalJobs += 1;
274
291
  if (this.totalJobs >= 200) this.recycleRequested = true;
@@ -300,7 +317,7 @@ let BrowserService = class BrowserService {
300
317
  const dir = this.cacheDir;
301
318
  try {
302
319
  if (!existsSync(dir)) return;
303
- logger.log(`Cleanup puppeteer cache on signal: ${dir}`);
320
+ logger.log(`Cleanup puppeteer cache: ${dir}`);
304
321
  await rmWithRetries(dir, 6);
305
322
  if (existsSync(dir)) {
306
323
  await sleep(100);
@@ -349,23 +366,6 @@ let BrowserService = class BrowserService {
349
366
  }
350
367
  return null;
351
368
  }
352
- registerCleanupHooks() {
353
- const cleanup = async (signal) => {
354
- try {
355
- Logger.log(`Received ${signal}, cleaning up puppeteer cache...`, "NestJsPdf");
356
- await this.cleanupCacheBestEffort();
357
- process.exit(0);
358
- } catch {
359
- process.exit(1);
360
- }
361
- };
362
- const cleanupHandler = (signal) => {
363
- cleanup(signal);
364
- };
365
- process.once("SIGTERM", cleanupHandler);
366
- process.once("SIGINT", cleanupHandler);
367
- process.once("exit", cleanupHandler);
368
- }
369
369
  loadBrowser() {
370
370
  let browser;
371
371
  if (this.options?.browser === void 0) browser = Browser.CHROMIUM;