@shad0wz7/nestjs-pdf 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,12 +7,13 @@
7
7
  [![codecov](https://codecov.io/github/ShadowZ11/nestjs-pdf/graph/badge.svg?token=K0MNB1ZKYK)](https://codecov.io/github/ShadowZ11/nestjs-pdf)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-6.0.3-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
9
9
 
10
- A NestJS library to generate and manipulate PDFs using Puppeteer and multiple template engines, including Handlebars, EJS, Pug, MJML, Nunjucks, Eta, Mustache and Liquid.
10
+ A NestJS library to generate and manipulate PDFs from multiple template engines (Handlebars, EJS, Pug, MJML, Nunjucks, Eta, Mustache and Liquid), printed by a local Puppeteer browser, a [Gotenberg](https://gotenberg.dev) server or the [Api2Pdf](https://www.api2pdf.com) API.
11
11
 
12
12
  Main features:
13
13
 
14
14
  - Generate PDFs from HTML, Handlebars, EJS, Pug, MJML, Nunjucks, Eta, Mustache or Liquid templates
15
- - Concurrency limiting for Puppeteer jobs (p-limit)
15
+ - Pluggable PDF providers: local Puppeteer (default), Gotenberg or Api2Pdf, behind the same service API
16
+ - Concurrency limiting for PDF jobs (p-limit)
16
17
  - Add signature fields based on a text anchor in an existing PDF
17
18
  - Text or image watermarks (centered or tiled) on generated or existing PDFs
18
19
  - Simple API (module and service) to integrate easily into a Nest application
@@ -37,6 +38,18 @@ yarn add @shad0wz7/nestjs-pdf
37
38
  pnpm add ../path/to/nestjs-pdf
38
39
  ```
39
40
 
41
+ ### PDF provider
42
+
43
+ Pick who prints the PDFs and install what it needs:
44
+
45
+ | Provider | Install | Notes |
46
+ | --------------------- | ------------------------------------------- | -------------------------------------------------------------------- |
47
+ | `puppeteer` (default) | `npm install puppeteer @puppeteer/browsers` | Local Chromium, downloaded on startup unless `executablePath` is set |
48
+ | `gotenberg` | nothing | Needs a [Gotenberg 8](https://gotenberg.dev) server |
49
+ | `api2pdf` | nothing | Needs an [Api2Pdf](https://www.api2pdf.com) API key |
50
+
51
+ `puppeteer` and `@puppeteer/browsers` are **optional peer dependencies**: with a remote provider, no browser is installed nor downloaded. The `puppeteer` provider needs **both** packages: if either is missing, the application fails on startup with an `EngineNotAvailableException` telling you what to install. With `executablePath`, the browser is not downloaded, so only `puppeteer` is needed. See [PDF providers](#pdf-providers) to configure Gotenberg or Api2Pdf.
52
+
40
53
  ### Template engines
41
54
 
42
55
  Template engines are **optional peer dependencies**: none of them is installed with the library. Install only the ones you use, as dependencies of your own project:
@@ -67,6 +80,8 @@ Anchor-based signature placement also relies on `pdfjs-dist`, which needs `@napi
67
80
 
68
81
  > **Upgrading from v3:** engines used to be installed automatically. If you relied on that, add the engines you use to your project's dependencies.
69
82
 
83
+ > **Upgrading from v4:** Puppeteer is no longer installed with the library. If you keep the default provider, add it to your project: `npm install puppeteer @puppeteer/browsers`. `NestjsPdfErrorCode` also gained a `RENDERER_CONFIGURATION_ERROR` member: update any exhaustive `Record<NestjsPdfErrorCode, …>` map. `pdfOptions` is now typed by the library's own `PdfOptions` (same shape as Puppeteer's `PDFOptions`) and `browser` accepts plain strings (`'chromium'`) as well as the `Browser` enum, so the published types no longer depend on Puppeteer.
84
+
70
85
  ## Quick start
71
86
 
72
87
  Import the module and configure it in your Nest application:
@@ -234,16 +249,92 @@ Good to know:
234
249
  - Names are checked by resolving them before the request, so a domain that changes its address between the check and the request (DNS rebinding) can slip through. Use `allowedHosts` (or `javascriptEnabled: false`) when the content is fully untrusted.
235
250
  - `window.open` pop-ups are blocked: the library no longer passes `--disable-popup-blocking` to Chrome. If you set `extraPuppeteerArgs`, do not add it back.
236
251
 
252
+ ## PDF providers
253
+
254
+ Templates, watermarks and signatures always run in your application; the provider only turns the rendered HTML into a PDF. Choose it with `provider` in `forRoot` / `forRootAsync` (it is ignored in per-call options):
255
+
256
+ ```ts
257
+ // Gotenberg (self-hosted): docker run --rm -p 3000:3000 gotenberg/gotenberg:8
258
+ NestjsPdfModule.forRoot({
259
+ provider: {
260
+ type: 'gotenberg',
261
+ url: 'http://localhost:3000',
262
+ // optional: when Gotenberg runs with --api-enable-basic-auth
263
+ basicAuth: { username: 'user', password: 'pass' },
264
+ // optional: extra headers, e.g. for an authenticating proxy
265
+ headers: { 'X-Api-Key': '...' },
266
+ },
267
+ pdfOptions: { format: 'A4', printBackground: true },
268
+ });
269
+
270
+ // Api2Pdf (SaaS)
271
+ NestjsPdfModule.forRootAsync({
272
+ inject: [ConfigService],
273
+ useFactory: (config: ConfigService) => ({
274
+ provider: { type: 'api2pdf', apiKey: config.getOrThrow('API2PDF_KEY') },
275
+ }),
276
+ });
277
+ ```
278
+
279
+ The service API does not change: `generatePdfFromHtml`, every `generatePdfFrom<Engine>*` method, `watermark` and `signal` work the same with every provider. A missing `url` / `apiKey` or an unknown `type` throws a `RendererConfigurationException` on startup.
280
+
281
+ ### Page options
282
+
283
+ Keep using `pdfOptions` (Puppeteer's format). For Gotenberg and Api2Pdf, these fields are translated: `format`, `width`, `height`, `margin` (numbers are pixels; strings in `px`, `in`, `cm` or `mm`), `landscape`, `printBackground`, `omitBackground`, `scale`, `pageRanges`, `displayHeaderFooter` with `headerTemplate` / `footerTemplate`, plus `preferCSSPageSize`, `tagged` and `outline` for Gotenberg. The other fields are ignored. Like the Puppeteer provider, the page is rendered with the `screen` media type, and with zero margins unless you set them.
284
+
285
+ Provider-specific options, per call or in `forRoot`:
286
+
287
+ ```ts
288
+ await pdfService.generatePdfFromHtml(
289
+ '<img src="logo.png"><link rel="stylesheet" href="style.css">',
290
+ {
291
+ gotenbergOptions: {
292
+ // files the HTML references by relative name, sent next to index.html
293
+ assets: [
294
+ {
295
+ filename: 'logo.png',
296
+ content: await readFile('logo.png'),
297
+ contentType: 'image/png',
298
+ },
299
+ {
300
+ filename: 'style.css',
301
+ content: 'body { font-family: sans-serif; }',
302
+ contentType: 'text/css',
303
+ },
304
+ ],
305
+ // any Gotenberg Chromium form field (PDF/A, wait...), wins over the derived ones
306
+ formFields: { pdfa: 'PDF/A-2b', waitDelay: '500ms' },
307
+ },
308
+ },
309
+ );
310
+
311
+ await pdfService.generatePdfFromHtml(html, {
312
+ // any Api2Pdf Chrome option, merged over the derived ones
313
+ api2pdfOptions: { fileName: 'invoice.pdf', options: { delay: 500 } },
314
+ });
315
+ ```
316
+
317
+ ### Good to know
318
+
319
+ - **Local files:** a remote provider cannot read your disk. With Gotenberg, send images, fonts and CSS as `assets`; with Api2Pdf, use public URLs or inline them (`data:` URIs).
320
+ - **`security` is Puppeteer-only:** the request filter runs in the local browser, so with a remote provider it throws a `RendererConfigurationException` instead of being silently skipped. With Gotenberg, restrict outbound requests on the server (`--chromium-allow-list`, `--chromium-deny-list`); with Api2Pdf, only render HTML you trust.
321
+ - **With Api2Pdf, data leaves your infrastructure:** the HTML is sent to a third-party service, which matters for personal data (GDPR). Gotenberg stays on your own servers.
322
+ - **Errors:** an HTTP error from the provider becomes a `PdfGenerationException` whose message holds the status and the start of the response body.
323
+ - **Browser options** (`headless`, `browser`, `browserTag`, `buildId`, `useLockedBrowser`, `executablePath`, `extraPuppeteerArgs`, `browserInstallBaseUrl`, `cleanupBrowserCacheOnExit`) only apply to the `puppeteer` provider.
324
+
237
325
  ## Options and configuration
238
326
 
239
- The library exposes Puppeteer options via the `PuppeteerParameters` interface (see `src/puppeteer/puppeteer-parameters.interface.ts`). You can configure:
327
+ The library exposes its options via the `PuppeteerParameters` interface (see `src/puppeteer/puppeteer-parameters.interface.ts`). You can configure:
240
328
 
241
329
  | | Description |
242
330
  | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
243
- | `pdfOptions` | The pdf options can be found on: https://pptr.dev/api/puppeteer.pdfoptions. Native Puppeteer options for `page.pdf` |
331
+ | `provider` | Who prints the PDF: `{ type: 'puppeteer' }` (default), `{ type: 'gotenberg', url, basicAuth?, headers? }` or `{ type: 'api2pdf', apiKey, baseUrl?, headers? }`. Module-level only. See [PDF providers](#pdf-providers) |
332
+ | `pdfOptions` | The pdf options can be found on: https://pptr.dev/api/puppeteer.pdfoptions. Native Puppeteer options for `page.pdf`. Remote providers translate the main ones, see [Page options](#page-options) |
333
+ | `gotenbergOptions` | Gotenberg provider only: `assets` (files sent next to `index.html`) and raw `formFields` |
334
+ | `api2pdfOptions` | Api2Pdf provider only: `fileName` and raw Chrome `options` |
244
335
  | `watermark` | Stamps a text or image watermark on the generated PDF: `text` or `image`, `opacity`, `rotation`, `fontSize`, `font`, `color`, `imageWidth`, `position`, `tileSpacing`, `pages`. See [Watermark](#watermark) |
245
336
  | `signal` | An `AbortSignal` that cancels the generation, including while it waits for a free slot. The promise rejects with `signal.reason`; use `AbortSignal.timeout(ms)` for a timeout. See [Cancellation and timeout](#cancellation-and-timeout) |
246
- | `security` | Filters what the rendered HTML may load (SSRF protection): `blockPrivateNetworks`, `allowedHosts`, `allowedFileRoots`, `javascriptEnabled`. Disabled unless set; pass `{}` for the defaults. See [Restricting what the HTML can load](#restricting-what-the-html-can-load-ssrf-protection) |
337
+ | `security` | Puppeteer provider only. Filters what the rendered HTML may load (SSRF protection): `blockPrivateNetworks`, `allowedHosts`, `allowedFileRoots`, `javascriptEnabled`. Disabled unless set; pass `{}` for the defaults. See [Restricting what the HTML can load](#restricting-what-the-html-can-load-ssrf-protection) |
247
338
  | `hbsOptions` | Handlebars configuration: `templateDirectory` (base dir for `renderFile`), `partialDirectory` (files registered as partials), `compileOptions`, `templateOptions`, and `helpers` (`{ name, fn }[]`). Like the other engines it can be set globally here or overridden per call (`generatePdfFromTemplateHbs*(..., { hbsOptions })`). Helpers/partials run on an isolated Handlebars environment (no global leakage). |
248
339
  | `ejsOptions` | The ejs options can be found on [EJS documentation](https://ejs.co/#options) |
249
340
  | `pugOptions` | The pug options can be found on [Pug documentation](https://pugjs.org/api/reference.html#options) |