@spinajs/templates-pdf 2.0.433 → 2.0.436

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/lib/cjs/index.js CHANGED
@@ -8,23 +8,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
12
  exports.PdfRenderer = void 0;
16
- const puppeteer_1 = __importDefault(require("puppeteer"));
17
- const exceptions_1 = require("@spinajs/exceptions");
13
+ const templates_puppeteer_1 = require("@spinajs/templates-puppeteer");
18
14
  const templates_1 = require("@spinajs/templates");
19
15
  const configuration_1 = require("@spinajs/configuration");
20
16
  const di_1 = require("@spinajs/di");
21
- const path_1 = require("path");
22
- const log_1 = require("@spinajs/log");
23
- const express_1 = __importDefault(require("express"));
24
- const cors_1 = __importDefault(require("cors"));
25
- require("@spinajs/templates-pug");
26
- const lodash_1 = __importDefault(require("lodash"));
27
- let PdfRenderer = class PdfRenderer extends templates_1.TemplateRenderer {
17
+ let PdfRenderer = class PdfRenderer extends templates_puppeteer_1.PuppeteerRenderer {
28
18
  get Type() {
29
19
  return 'pdf';
30
20
  }
@@ -38,259 +28,18 @@ let PdfRenderer = class PdfRenderer extends templates_1.TemplateRenderer {
38
28
  __checkInstance__(creationOptions) {
39
29
  return JSON.stringify(this.pdfOptions) === JSON.stringify(creationOptions);
40
30
  }
41
- async renderToFile(template, model, filePath, language) {
42
- let server = null;
43
- let browser = null;
44
- try {
45
- this.Log.timeStart(`pdf-template-rendering-${filePath}`);
46
- this.Log.trace(`Rendering pdf template ${template} to file ${filePath}`);
47
- const templateBasePath = (0, path_1.dirname)(template);
48
- // fire up local http server for serving images etc
49
- // becouse chromium prevents from reading local files when not
50
- // rendering file with file:// protocol for security reasons
51
- server = await this.runLocalServer(templateBasePath);
52
- const httpPort = server.address().port;
53
- const compiledTemplate = await this.TemplatingService.render((0, path_1.join)(templateBasePath, (0, path_1.basename)(template, '.pdf')) + '.pug', {
54
- // add template temporary server port
55
- // so we can use it to render images in template
56
- __http_template_port__: httpPort,
57
- // for convinience add full url to local http server
58
- __http_template_address__: `http://localhost:${httpPort}`,
59
- ...model,
60
- }, language);
61
- const launchOptions = {
62
- ...this.Options.args,
63
- ...(this.Options.executablePath && {
64
- executablePath: this.Options.executablePath,
65
- }),
66
- };
67
- browser = await puppeteer_1.default.launch(launchOptions);
68
- const page = await browser.newPage();
69
- // Skip timeouts in debug mode
70
- if (!this.Options.debug?.close) {
71
- page.setDefaultNavigationTimeout(this.Options.navigationTimeout || 30000); // Default 30s
72
- page.setDefaultTimeout(this.Options.renderTimeout || 30000); // Default 30s
73
- }
74
- // Set up render timeout (skip in debug mode)
75
- let renderTimeout;
76
- if (!this.Options.debug?.close) {
77
- const timeoutMs = this.Options.renderTimeout || 30000;
78
- renderTimeout = setTimeout(async () => {
79
- this.Log.warn(`PDF render timeout (${timeoutMs}ms) - forcing cleanup`);
80
- try {
81
- if (page)
82
- await page.close().catch(() => { });
83
- if (browser)
84
- await this.forceCloseBrowser(browser);
85
- }
86
- catch (err) {
87
- this.Log.error('Error during timeout cleanup:', err);
88
- }
89
- }, timeoutMs);
90
- }
91
- // Add event listeners with explicit cleanup tracking
92
- const eventCleanup = this.addPageEventListeners(page);
93
- try {
94
- await page.setBypassCSP(true);
95
- await page.setContent(compiledTemplate);
96
- await page.pdf({
97
- path: filePath,
98
- ...this.pdfOptions,
99
- });
100
- // Clear timeout on successful completion
101
- if (renderTimeout) {
102
- clearTimeout(renderTimeout);
103
- renderTimeout = undefined;
104
- }
105
- // Clean up event listeners
106
- eventCleanup();
107
- }
108
- catch (renderError) {
109
- // Clear timeout on error
110
- if (renderTimeout) {
111
- clearTimeout(renderTimeout);
112
- renderTimeout = undefined;
113
- }
114
- this.Log.error(renderError, `Error during PDF rendering for template ${template}`);
115
- throw renderError;
116
- }
117
- }
118
- catch (err) {
119
- this.Log.error(err, `Error rendering pdf template ${template} to file ${filePath}`);
120
- throw err;
121
- }
122
- finally {
123
- const duration = this.Log.timeEnd(`pdf-template-rendering-${filePath}`);
124
- this.Log.trace(`Ended rendering pdf template ${template} to file ${filePath}, took: ${duration}ms`);
125
- if (duration > this.Options.renderDurationWarning) {
126
- this.Log.warn(`Rendering pdf template ${template} to file ${filePath} took too long.`);
127
- }
128
- // Skip browser cleanup if debug.close is false (keep browser open for inspection)
129
- if (browser && this.Options.debug?.close !== false) {
130
- await this.safeBrowserCleanup(browser);
131
- }
132
- else if (browser) {
133
- this.Log.info('Browser kept open for debugging (debug.close=false)');
134
- }
135
- if (server) {
136
- await this.safeServerCleanup(server);
137
- }
138
- }
139
- }
140
- async render(_templateName, _model, _language) {
141
- throw new exceptions_1.NotSupported('cannot render pdf template to string');
142
- }
143
- // no compilation at start
144
- async compile(_path) { }
145
- async runLocalServer(basePath) {
146
- const self = this;
147
- const app = (0, express_1.default)();
148
- app.use((0, cors_1.default)());
149
- app.use(express_1.default.static(basePath));
150
- return new Promise((resolve, reject) => {
151
- const server = app
152
- // if no port is provided express will choose random port to start (available)
153
- // if not, we will get random from range in config
154
- .listen(this.Options.static.portRange.length === 0
155
- ? 0
156
- : lodash_1.default.random(this.Options.static.portRange[0], this.Options.static.portRange[1]))
157
- .on('listening', function () {
158
- self.Log.trace(`PDF image server started on port ${this.address().port}`);
159
- self.Log.trace(`PDF static file dir at ${basePath}`);
160
- resolve(this);
161
- })
162
- .on('error', (err) => {
163
- self.Log.error(err, `PDF image server cannot start`);
164
- // Clean up the failed server
165
- if (server) {
166
- server.close(() => {
167
- reject(err);
168
- });
169
- }
170
- else {
171
- reject(err);
172
- }
173
- });
174
- // Set a timeout for server startup
175
- setTimeout(() => {
176
- if (!server.listening) {
177
- server.close();
178
- reject(new Error('Server startup timeout'));
179
- }
180
- }, 10000);
31
+ async performRender(page, filePath) {
32
+ await page.pdf({
33
+ path: filePath,
34
+ ...this.pdfOptions,
181
35
  });
182
36
  }
183
- /**
184
- * Enhanced browser cleanup with error handling
185
- */
186
- async safeBrowserCleanup(browser) {
187
- try {
188
- // First try to close all pages
189
- const pages = await browser.pages();
190
- await Promise.allSettled(pages.map(page => page.close()));
191
- // Then close the browser normally
192
- await browser.close();
193
- }
194
- catch (err) {
195
- this.Log.warn(`Error during normal browser cleanup: ${err.message}`);
196
- // Force kill if normal close fails
197
- try {
198
- await this.forceCloseBrowser(browser);
199
- }
200
- catch (killErr) {
201
- this.Log.error(`Failed to force kill browser: ${killErr.message}`);
202
- }
203
- }
204
- }
205
- /**
206
- * Force close browser with process termination
207
- */
208
- async forceCloseBrowser(browser) {
209
- try {
210
- const process = browser.process();
211
- if (process) {
212
- process.kill('SIGKILL');
213
- this.Log.warn('Browser process force killed');
214
- }
215
- }
216
- catch (err) {
217
- this.Log.error(`Error force killing browser process: ${err.message}`);
218
- }
219
- }
220
- /**
221
- * Enhanced server cleanup with timeout
222
- */
223
- async safeServerCleanup(server) {
224
- try {
225
- await new Promise((resolve, reject) => {
226
- const timeout = setTimeout(() => {
227
- reject(new Error('Server close timeout'));
228
- }, 5000);
229
- server.close((err) => {
230
- clearTimeout(timeout);
231
- if (err)
232
- reject(err);
233
- else
234
- resolve();
235
- });
236
- });
237
- }
238
- catch (err) {
239
- this.Log.warn(`Error closing server: ${err.message}`);
240
- // Force close connections if available
241
- try {
242
- if ('closeAllConnections' in server) {
243
- server.closeAllConnections();
244
- }
245
- }
246
- catch (forceErr) {
247
- this.Log.error(`Error force closing server connections: ${forceErr.message}`);
248
- }
249
- }
250
- }
251
- /**
252
- * Add page event listeners with cleanup function
253
- */
254
- addPageEventListeners(page) {
255
- const listeners = {
256
- console: (message) => this.Log.trace(`${message.type().substr(0, 3).toUpperCase()} ${message.text()}`),
257
- pageerror: ({ message }) => this.Log.error(message),
258
- response: (response) => this.Log.trace(`${response.status()} ${response.url()}`),
259
- requestfailed: (request) => this.Log.error(`${request.failure().errorText} ${request.url()}`)
260
- };
261
- // Add listeners
262
- page.on('console', listeners.console);
263
- page.on('pageerror', listeners.pageerror);
264
- page.on('response', listeners.response);
265
- page.on('requestfailed', listeners.requestfailed);
266
- // Return cleanup function
267
- return () => {
268
- try {
269
- page.removeListener('console', listeners.console);
270
- page.removeListener('pageerror', listeners.pageerror);
271
- page.removeListener('response', listeners.response);
272
- page.removeListener('requestfailed', listeners.requestfailed);
273
- }
274
- catch (err) {
275
- this.Log.warn(`Error removing page listeners: ${err.message}`);
276
- }
277
- };
278
- }
279
37
  };
280
38
  exports.PdfRenderer = PdfRenderer;
281
- PdfRenderer.USED_PORTS = [];
282
39
  __decorate([
283
40
  (0, configuration_1.Config)('templates.pdf'),
284
41
  __metadata("design:type", Object)
285
42
  ], PdfRenderer.prototype, "Options", void 0);
286
- __decorate([
287
- (0, log_1.Logger)('pdf-templates'),
288
- __metadata("design:type", log_1.Log)
289
- ], PdfRenderer.prototype, "Log", void 0);
290
- __decorate([
291
- (0, di_1.LazyInject)(),
292
- __metadata("design:type", templates_1.Templates)
293
- ], PdfRenderer.prototype, "TemplatingService", void 0);
294
43
  exports.PdfRenderer = PdfRenderer = __decorate([
295
44
  (0, di_1.Injectable)(templates_1.TemplateRenderer),
296
45
  (0, di_1.PerInstanceCheck)(),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,sEAA4F;AAC5F,kDAAsD;AACtD,0DAAgD;AAChD,oCAA2E;AAIpE,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,uCAAiB;IAOhD,IAAW,IAAI;QACb,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAW,SAAS;QAClB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,YAAsB,UAAsB;QAC1C,KAAK,EAAE,CAAC;QADY,eAAU,GAAV,UAAU,CAAY;IAE5C,CAAC;IAED,iBAAiB,CAAC,eAAoB;QACpC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAC7E,CAAC;IAES,KAAK,CAAC,aAAa,CAAC,IAAU,EAAE,QAAgB;QACxD,MAAM,IAAI,CAAC,GAAG,CAAC;YACb,IAAI,EAAE,QAAQ;YACd,GAAG,IAAI,CAAC,UAAU;SACnB,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AA7BY,kCAAW;AAKZ;IADT,IAAA,sBAAM,EAAC,eAAe,CAAC;;4CACqB;sBALlC,WAAW;IAFvB,IAAA,eAAU,EAAC,4BAAgB,CAAC;IAC5B,IAAA,qBAAgB,GAAE;;GACN,WAAW,CA6BvB"}
@@ -0,0 +1,82 @@
1
+ import { Browser, Page, LaunchOptions } from 'puppeteer';
2
+ import { TemplateRenderer, Templates } from '@spinajs/templates';
3
+ import { Log } from '@spinajs/log';
4
+ import * as http from 'http';
5
+ export interface IPdfRendererOptions {
6
+ static: {
7
+ portRange: number[];
8
+ };
9
+ args: LaunchOptions;
10
+ /**
11
+ * Optional path to Chrome/Chromium executable.
12
+ * Useful when running in environments where Puppeteer cannot download Chromium.
13
+ * If provided, overrides args.executablePath.
14
+ */
15
+ executablePath?: string;
16
+ renderDurationWarning: number;
17
+ navigationTimeout?: number;
18
+ renderTimeout?: number;
19
+ /**
20
+ * Debug options
21
+ */
22
+ debug?: {
23
+ /**
24
+ * If true, browser will remain open after rendering for inspection
25
+ * Use it with headless: false in args to see the browser window ( puppetter.launch args )
26
+ */
27
+ close?: boolean;
28
+ };
29
+ }
30
+ export interface RenderContext {
31
+ server: http.Server;
32
+ browser: Browser;
33
+ page: Page;
34
+ compiledTemplate: string;
35
+ renderTimeout?: NodeJS.Timeout;
36
+ eventCleanup: () => void;
37
+ }
38
+ /**
39
+ * Base class for PDF-based template renderers
40
+ * Provides common functionality for rendering templates using Puppeteer
41
+ */
42
+ export declare abstract class BasePdfTemplate extends TemplateRenderer {
43
+ protected Options: IPdfRendererOptions;
44
+ protected Log: Log;
45
+ protected TemplatingService: Templates;
46
+ protected static USED_PORTS: number[];
47
+ renderToFile(template: string, model: any, filePath: string, language?: string): Promise<void>;
48
+ /**
49
+ * Setup the rendering context (server, browser, page, compiled template)
50
+ */
51
+ protected setupRenderContext(template: string, model: any, language?: string): Promise<RenderContext>;
52
+ /**
53
+ * Perform the actual rendering operation - to be implemented by subclasses
54
+ */
55
+ protected abstract performRender(context: RenderContext, filePath: string): Promise<void>;
56
+ /**
57
+ * Cleanup resources after rendering
58
+ */
59
+ protected cleanup(context: Partial<RenderContext>): Promise<void>;
60
+ /**
61
+ * Run local HTTP server for serving static assets
62
+ */
63
+ protected runLocalServer(basePath: string): Promise<http.Server>;
64
+ /**
65
+ * Enhanced browser cleanup with error handling
66
+ */
67
+ protected safeBrowserCleanup(browser: Browser): Promise<void>;
68
+ /**
69
+ * Force close browser with process termination
70
+ */
71
+ protected forceCloseBrowser(browser: Browser): Promise<void>;
72
+ /**
73
+ * Enhanced server cleanup with timeout
74
+ */
75
+ protected safeServerCleanup(server: http.Server): Promise<void>;
76
+ /**
77
+ * Add page event listeners with cleanup function
78
+ */
79
+ protected addPageEventListeners(page: Page): () => void;
80
+ protected compile(_path: string): Promise<void>;
81
+ }
82
+ //# sourceMappingURL=BasePdfTemplate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BasePdfTemplate.d.ts","sourceRoot":"","sources":["../../src/BasePdfTemplate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAwB,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAIjE,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAK7B,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,IAAI,EAAE,aAAa,CAAC;IAEpB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,KAAK,CAAC,EAAE;QACN;;;WAGG;QACH,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;IAC/B,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,8BAAsB,eAAgB,SAAQ,gBAAgB;IAE5D,SAAS,CAAC,OAAO,EAAE,mBAAmB,CAAC;IAGvC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,iBAAiB,EAAE,SAAS,CAAC;IAEvC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAM;IAE9B,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B3G;;OAEG;cACa,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,GAAG,EACV,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC;IA+DzB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEzF;;OAEG;cACa,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAavE;;OAEG;cACa,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;IAuCtE;;OAEG;cACa,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBnE;;OAEG;cACa,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlE;;OAEG;cACa,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BrE;;OAEG;IACH,SAAS,CAAC,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,IAAI;cA0BvC,OAAO,CAAC,KAAK,EAAE,MAAM;CACtC"}
@@ -0,0 +1,263 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { default as puppeteer } from 'puppeteer';
11
+ import { TemplateRenderer, Templates } from '@spinajs/templates';
12
+ import { Config } from '@spinajs/configuration';
13
+ import { LazyInject } from '@spinajs/di';
14
+ import { basename, dirname, join } from 'path';
15
+ import { Log, Logger } from '@spinajs/log';
16
+ import Express from 'express';
17
+ import cors from 'cors';
18
+ import _ from 'lodash';
19
+ /**
20
+ * Base class for PDF-based template renderers
21
+ * Provides common functionality for rendering templates using Puppeteer
22
+ */
23
+ export class BasePdfTemplate extends TemplateRenderer {
24
+ async renderToFile(template, model, filePath, language) {
25
+ let context = {};
26
+ try {
27
+ this.Log.timeStart(`template-rendering-${filePath}`);
28
+ this.Log.trace(`Rendering template ${template} to file ${filePath}`);
29
+ context = await this.setupRenderContext(template, model, language);
30
+ await this.performRender(context, filePath);
31
+ if (context.renderTimeout) {
32
+ clearTimeout(context.renderTimeout);
33
+ }
34
+ if (context.eventCleanup) {
35
+ context.eventCleanup();
36
+ }
37
+ }
38
+ catch (err) {
39
+ this.Log.error(err, `Error rendering template ${template} to file ${filePath}`);
40
+ throw err;
41
+ }
42
+ finally {
43
+ const duration = this.Log.timeEnd(`template-rendering-${filePath}`);
44
+ if (duration > this.Options.renderDurationWarning) {
45
+ this.Log.warn(`Rendering took too long: ${duration}ms`);
46
+ }
47
+ await this.cleanup(context);
48
+ }
49
+ }
50
+ /**
51
+ * Setup the rendering context (server, browser, page, compiled template)
52
+ */
53
+ async setupRenderContext(template, model, language) {
54
+ const templateBasePath = dirname(template);
55
+ // Fire up local http server for serving images etc
56
+ const server = await this.runLocalServer(templateBasePath);
57
+ const httpPort = server.address().port;
58
+ const compiledTemplate = await this.TemplatingService.render(join(templateBasePath, basename(template, this.Extension)) + '.pug', {
59
+ __http_template_port__: httpPort,
60
+ __http_template_address__: `http://localhost:${httpPort}`,
61
+ ...model,
62
+ }, language);
63
+ const launchOptions = {
64
+ ...this.Options.args,
65
+ ...(this.Options.executablePath && {
66
+ executablePath: this.Options.executablePath,
67
+ }),
68
+ };
69
+ const browser = await puppeteer.launch(launchOptions);
70
+ const page = await browser.newPage();
71
+ // Skip timeouts in debug mode
72
+ if (!this.Options.debug?.close) {
73
+ page.setDefaultNavigationTimeout(this.Options.navigationTimeout || 30000);
74
+ page.setDefaultTimeout(this.Options.renderTimeout || 30000);
75
+ }
76
+ // Set up render timeout (skip in debug mode)
77
+ let renderTimeout;
78
+ if (!this.Options.debug?.close) {
79
+ const timeoutMs = this.Options.renderTimeout || 30000;
80
+ renderTimeout = setTimeout(async () => {
81
+ this.Log.warn(`Render timeout (${timeoutMs}ms) - forcing cleanup`);
82
+ try {
83
+ if (page)
84
+ await page.close().catch(() => { });
85
+ if (browser)
86
+ await this.forceCloseBrowser(browser);
87
+ }
88
+ catch (err) {
89
+ this.Log.error('Error during timeout cleanup:', err);
90
+ }
91
+ }, timeoutMs);
92
+ }
93
+ const eventCleanup = this.addPageEventListeners(page);
94
+ await page.setBypassCSP(true);
95
+ await page.setContent(compiledTemplate);
96
+ return {
97
+ server,
98
+ browser,
99
+ page,
100
+ compiledTemplate,
101
+ renderTimeout,
102
+ eventCleanup,
103
+ };
104
+ }
105
+ /**
106
+ * Cleanup resources after rendering
107
+ */
108
+ async cleanup(context) {
109
+ // Skip browser cleanup if debug.close is false
110
+ if (context.browser && this.Options.debug?.close !== false) {
111
+ await this.safeBrowserCleanup(context.browser);
112
+ }
113
+ else if (context.browser) {
114
+ this.Log.info('Browser kept open for debugging (debug.close=false)');
115
+ }
116
+ if (context.server) {
117
+ await this.safeServerCleanup(context.server);
118
+ }
119
+ }
120
+ /**
121
+ * Run local HTTP server for serving static assets
122
+ */
123
+ async runLocalServer(basePath) {
124
+ const self = this;
125
+ const app = Express();
126
+ app.use(cors());
127
+ app.use(Express.static(basePath));
128
+ return new Promise((resolve, reject) => {
129
+ const server = app
130
+ .listen(this.Options.static.portRange.length === 0
131
+ ? 0
132
+ : _.random(this.Options.static.portRange[0], this.Options.static.portRange[1]))
133
+ .on('listening', function () {
134
+ self.Log.trace(`Static server started on port ${this.address().port}`);
135
+ self.Log.trace(`Static file dir at ${basePath}`);
136
+ resolve(this);
137
+ })
138
+ .on('error', (err) => {
139
+ self.Log.error(err, `Static server cannot start`);
140
+ if (server) {
141
+ server.close(() => {
142
+ reject(err);
143
+ });
144
+ }
145
+ else {
146
+ reject(err);
147
+ }
148
+ });
149
+ setTimeout(() => {
150
+ if (!server.listening) {
151
+ server.close();
152
+ reject(new Error('Server startup timeout'));
153
+ }
154
+ }, 10000);
155
+ });
156
+ }
157
+ /**
158
+ * Enhanced browser cleanup with error handling
159
+ */
160
+ async safeBrowserCleanup(browser) {
161
+ try {
162
+ const pages = await browser.pages();
163
+ await Promise.allSettled(pages.map((page) => page.close()));
164
+ await browser.close();
165
+ }
166
+ catch (err) {
167
+ this.Log.warn(`Error during normal browser cleanup: ${err.message}`);
168
+ try {
169
+ await this.forceCloseBrowser(browser);
170
+ }
171
+ catch (killErr) {
172
+ this.Log.error(`Failed to force kill browser: ${killErr.message}`);
173
+ }
174
+ }
175
+ }
176
+ /**
177
+ * Force close browser with process termination
178
+ */
179
+ async forceCloseBrowser(browser) {
180
+ try {
181
+ const process = browser.process();
182
+ if (process) {
183
+ process.kill('SIGKILL');
184
+ this.Log.warn('Browser process force killed');
185
+ }
186
+ }
187
+ catch (err) {
188
+ this.Log.error(`Error force killing browser process: ${err.message}`);
189
+ }
190
+ }
191
+ /**
192
+ * Enhanced server cleanup with timeout
193
+ */
194
+ async safeServerCleanup(server) {
195
+ try {
196
+ await new Promise((resolve, reject) => {
197
+ const timeout = setTimeout(() => {
198
+ reject(new Error('Server close timeout'));
199
+ }, 5000);
200
+ server.close((err) => {
201
+ clearTimeout(timeout);
202
+ if (err)
203
+ reject(err);
204
+ else
205
+ resolve();
206
+ });
207
+ });
208
+ }
209
+ catch (err) {
210
+ this.Log.warn(`Error closing server: ${err.message}`);
211
+ try {
212
+ if ('closeAllConnections' in server) {
213
+ server.closeAllConnections();
214
+ }
215
+ }
216
+ catch (forceErr) {
217
+ this.Log.error(`Error force closing server connections: ${forceErr.message}`);
218
+ }
219
+ }
220
+ }
221
+ /**
222
+ * Add page event listeners with cleanup function
223
+ */
224
+ addPageEventListeners(page) {
225
+ const listeners = {
226
+ console: (message) => this.Log.trace(`${message.type().substr(0, 3).toUpperCase()} ${message.text()}`),
227
+ pageerror: ({ message }) => this.Log.error(message),
228
+ response: (response) => this.Log.trace(`${response.status()} ${response.url()}`),
229
+ requestfailed: (request) => this.Log.error(`${request.failure().errorText} ${request.url()}`),
230
+ };
231
+ page.on('console', listeners.console);
232
+ page.on('pageerror', listeners.pageerror);
233
+ page.on('response', listeners.response);
234
+ page.on('requestfailed', listeners.requestfailed);
235
+ return () => {
236
+ try {
237
+ page.removeAllListeners('console');
238
+ page.removeAllListeners('pageerror');
239
+ page.removeAllListeners('response');
240
+ page.removeAllListeners('requestfailed');
241
+ }
242
+ catch (err) {
243
+ this.Log.warn(`Error removing page listeners: ${err.message}`);
244
+ }
245
+ };
246
+ }
247
+ // No compilation at start
248
+ async compile(_path) { }
249
+ }
250
+ BasePdfTemplate.USED_PORTS = [];
251
+ __decorate([
252
+ Config('templates.pdf'),
253
+ __metadata("design:type", Object)
254
+ ], BasePdfTemplate.prototype, "Options", void 0);
255
+ __decorate([
256
+ Logger('pdf-templates'),
257
+ __metadata("design:type", Log)
258
+ ], BasePdfTemplate.prototype, "Log", void 0);
259
+ __decorate([
260
+ LazyInject(),
261
+ __metadata("design:type", Templates)
262
+ ], BasePdfTemplate.prototype, "TemplatingService", void 0);
263
+ //# sourceMappingURL=BasePdfTemplate.js.map