@ahmedrowaihi/pdf-forge-printer 1.0.0-canary.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/LICENSE.md ADDED
@@ -0,0 +1,8 @@
1
+ Copyright 2024 Plus Five Five, Inc
2
+ Copyright 2025 ahmedrowaihi (fork modifications)
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # @ahmedrowaihi/pdf-forge-printer
2
+
3
+ Playwright-based PDF and screenshot rendering service for React PDF Forge.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @ahmedrowaihi/pdf-forge-printer playwright
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Usage
14
+
15
+ ```typescript
16
+ import { PlaywrightPdfService } from '@ahmedrowaihi/pdf-forge-printer';
17
+
18
+ const pdfService = new PlaywrightPdfService();
19
+
20
+ // Generate PDF
21
+ const pdfBuffer = await pdfService.render({
22
+ html: '<html>...</html>',
23
+ outputType: 'pdf',
24
+ darkMode: false,
25
+ });
26
+
27
+ // Generate Screenshot
28
+ const screenshotBuffer = await pdfService.render({
29
+ html: '<html>...</html>',
30
+ outputType: 'screenshot',
31
+ darkMode: true,
32
+ });
33
+ ```
34
+
35
+ ### With Custom Logger
36
+
37
+ ```typescript
38
+ import {
39
+ PlaywrightPdfService,
40
+ ConsoleLogger,
41
+ } from '@ahmedrowaihi/pdf-forge-printer';
42
+
43
+ const logger = new ConsoleLogger();
44
+ const pdfService = new PlaywrightPdfService(logger);
45
+ ```
46
+
47
+ ### From URL
48
+
49
+ ```typescript
50
+ const pdfBuffer = await pdfService.render({
51
+ url: 'https://example.com',
52
+ outputType: 'pdf',
53
+ });
54
+ ```
55
+
56
+ ## API
57
+
58
+ ### `PlaywrightPdfService`
59
+
60
+ #### Constructor
61
+
62
+ ```typescript
63
+ constructor(logger?: PdfLogger)
64
+ ```
65
+
66
+ - `logger` (optional): Custom logger instance. Defaults to `ConsoleLogger`.
67
+
68
+ #### `render(input)`
69
+
70
+ Renders HTML or URL to PDF or screenshot.
71
+
72
+ **Parameters:**
73
+
74
+ ```typescript
75
+ {
76
+ html?: string; // HTML content to render
77
+ url?: string; // URL to render (must provide html OR url)
78
+ outputType: 'pdf' | 'screenshot';
79
+ darkMode?: boolean; // Enable dark mode (default: false)
80
+ }
81
+ ```
82
+
83
+ **Returns:** `Promise<Uint8Array>` - Buffer containing PDF or PNG image
84
+
85
+ **Example:**
86
+
87
+ ```typescript
88
+ const buffer = await pdfService.render({
89
+ html: '<html><body>Hello World</body></html>',
90
+ outputType: 'pdf',
91
+ darkMode: false,
92
+ });
93
+ ```
94
+
95
+ ## Features
96
+
97
+ - ✅ **A4 Format Only** - Simplified to A4 paper size
98
+ - ✅ **Dark Mode Support** - Native Playwright colorScheme emulation + class-based theming
99
+ - ✅ **Print Media Emulation** - Automatically applies `@media print` styles for PDFs
100
+ - ✅ **High-Quality Screenshots** - Full-page screenshots with disabled animations
101
+ - ✅ **CSS @page Support** - Respects `@page` CSS rules via `preferCSSPageSize: true`
102
+ - ✅ **Zero Margins** - Clean edge-to-edge rendering
103
+
104
+ ## Configuration
105
+
106
+ ### Environment Variables
107
+
108
+ - `CHROMIUM_EXECUTABLE_PATH` - Path to custom Chromium executable (optional)
109
+
110
+ ### Default Settings
111
+
112
+ - **PDF Format:** A4 (210mm × 297mm)
113
+ - **Margins:** 0px on all sides
114
+ - **Print Background:** Enabled
115
+ - **Screenshot Scale:** CSS pixels (keeps file size small)
116
+ - **Animations:** Disabled for screenshots
117
+ - **Viewport:** 794px × 1123px (A4 at 96 DPI)
118
+
119
+ ## How It Works
120
+
121
+ 1. Launches headless Chromium browser
122
+ 2. Creates a context with emulation options (colorScheme, locale, viewport)
123
+ 3. Loads HTML content or navigates to URL
124
+ 4. Applies dark mode class if requested
125
+ 5. Emulates print media for PDF generation
126
+ 6. Captures PDF or screenshot using Playwright's native APIs
127
+ 7. Returns buffer as `Uint8Array`
128
+
129
+ ## Integration with React PDF Forge
130
+
131
+ This package is used by `@ahmedrowaihi/pdf-forge-preview` for exporting templates. It works seamlessly with:
132
+
133
+ - Playwright handles page size via `format: 'A4'` and `emulateMedia({ media: 'print' })`
134
+ - `Theme` component - Class-based theming system
135
+ - `PrintStyles` component - Wraps `@media print` styles
136
+
137
+ ## License
138
+
139
+ MIT
@@ -0,0 +1,29 @@
1
+ //#region src/logger.d.ts
2
+ interface PdfLogger {
3
+ debug(message: string): void;
4
+ log(message: string): void;
5
+ warn(message: string): void;
6
+ error(message: string, error?: unknown): void;
7
+ }
8
+ declare class ConsoleLogger implements PdfLogger {
9
+ debug(message: string): void;
10
+ log(message: string): void;
11
+ warn(message: string): void;
12
+ error(message: string, error?: unknown): void;
13
+ }
14
+ //#endregion
15
+ //#region src/playwright-pdf.service.d.ts
16
+ declare class PlaywrightPdfService {
17
+ private readonly logger;
18
+ constructor(logger?: PdfLogger);
19
+ private launchBrowser;
20
+ render(input: {
21
+ html?: string;
22
+ url?: string;
23
+ outputType: 'pdf' | 'screenshot';
24
+ darkMode?: boolean;
25
+ }): Promise<Uint8Array>;
26
+ }
27
+ //#endregion
28
+ export { ConsoleLogger, type PdfLogger, PlaywrightPdfService };
29
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/logger.ts","../src/playwright-pdf.service.ts"],"sourcesContent":[],"mappings":";UAAiB,SAAA;EAAA,KAAA,CAAA,OAAS,EAAA,MAAA,CAAA,EAAA,IAAA;EAOb,GAAA,CAAA,OAAA,EAAA,MAAc,CAAA,EAAA,IAAA;;;;ACGd,cDHA,aAAA,YAAyB,SCGL,CAAA;EAGX,KAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAwCR,GAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAR,IAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAO,KAAA,CAAA,OAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EAAA,OAAA,CAAA,EAAA,IAAA;;;;ADrDI,cCUJ,oBAAA,CDVa;EAOb,iBAAc,MAAA;uBCML;;;IAHT,IAAA,CAAA,EAAA,MAAA;IAGS,GAAA,CAAA,EAAA,MAAA;IAwCR,UAAA,EAAA,KAAA,GAAA,YAAA;IAAR,QAAA,CAAA,EAAA,OAAA;EAAO,CAAA,CAAA,EAAP,OAAO,CAAC,UAAD,CAAA"}
@@ -0,0 +1,29 @@
1
+ //#region src/logger.d.ts
2
+ interface PdfLogger {
3
+ debug(message: string): void;
4
+ log(message: string): void;
5
+ warn(message: string): void;
6
+ error(message: string, error?: unknown): void;
7
+ }
8
+ declare class ConsoleLogger implements PdfLogger {
9
+ debug(message: string): void;
10
+ log(message: string): void;
11
+ warn(message: string): void;
12
+ error(message: string, error?: unknown): void;
13
+ }
14
+ //#endregion
15
+ //#region src/playwright-pdf.service.d.ts
16
+ declare class PlaywrightPdfService {
17
+ private readonly logger;
18
+ constructor(logger?: PdfLogger);
19
+ private launchBrowser;
20
+ render(input: {
21
+ html?: string;
22
+ url?: string;
23
+ outputType: 'pdf' | 'screenshot';
24
+ darkMode?: boolean;
25
+ }): Promise<Uint8Array>;
26
+ }
27
+ //#endregion
28
+ export { ConsoleLogger, type PdfLogger, PlaywrightPdfService };
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/logger.ts","../src/playwright-pdf.service.ts"],"sourcesContent":[],"mappings":";UAAiB,SAAA;EAAA,KAAA,CAAA,OAAS,EAAA,MAAA,CAAA,EAAA,IAAA;EAOb,GAAA,CAAA,OAAA,EAAA,MAAc,CAAA,EAAA,IAAA;;;;ACGd,cDHA,aAAA,YAAyB,SCGL,CAAA;EAGX,KAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAwCR,GAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAR,IAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAO,KAAA,CAAA,OAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EAAA,OAAA,CAAA,EAAA,IAAA;;;;ADrDI,cCUJ,oBAAA,CDVa;EAOb,iBAAc,MAAA;uBCML;;;IAHT,IAAA,CAAA,EAAA,MAAA;IAGS,GAAA,CAAA,EAAA,MAAA;IAwCR,UAAA,EAAA,KAAA,GAAA,YAAA;IAAR,QAAA,CAAA,EAAA,OAAA;EAAO,CAAA,CAAA,EAAP,OAAO,CAAC,UAAD,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,157 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let node_fs_promises = require("node:fs/promises");
25
+ node_fs_promises = __toESM(node_fs_promises);
26
+ let playwright = require("playwright");
27
+ playwright = __toESM(playwright);
28
+
29
+ //#region src/logger.ts
30
+ var ConsoleLogger = class {
31
+ debug(message) {
32
+ if (process.env.NODE_ENV === "development") console.debug(`[PDF Printer] ${message}`);
33
+ }
34
+ log(message) {
35
+ console.log(`[PDF Printer] ${message}`);
36
+ }
37
+ warn(message) {
38
+ console.warn(`[PDF Printer] ${message}`);
39
+ }
40
+ error(message, error) {
41
+ console.error(`[PDF Printer] ${message}`, error);
42
+ }
43
+ };
44
+
45
+ //#endregion
46
+ //#region src/playwright-pdf.service.ts
47
+ const A4_WIDTH = 794;
48
+ const A4_HEIGHT = 1123;
49
+ var PlaywrightPdfService = class {
50
+ constructor(logger = new ConsoleLogger()) {
51
+ this.logger = logger;
52
+ }
53
+ async launchBrowser() {
54
+ const launchOptions = {
55
+ headless: true,
56
+ args: [
57
+ "--no-sandbox",
58
+ "--disable-setuid-sandbox",
59
+ "--disable-web-security",
60
+ "--disable-dev-shm-usage",
61
+ "--disable-blink-features=AutomationControlled",
62
+ "--disable-features=IsolateOrigins,site-per-process"
63
+ ]
64
+ };
65
+ if (process.env.CHROMIUM_EXECUTABLE_PATH) try {
66
+ await (0, node_fs_promises.access)(process.env.CHROMIUM_EXECUTABLE_PATH);
67
+ launchOptions.executablePath = process.env.CHROMIUM_EXECUTABLE_PATH;
68
+ this.logger.debug(`Using system Chromium at: ${process.env.CHROMIUM_EXECUTABLE_PATH}`);
69
+ } catch {
70
+ this.logger.warn(`Chromium path specified but not found: ${process.env.CHROMIUM_EXECUTABLE_PATH}, using Playwright's bundled browser`);
71
+ }
72
+ return playwright.chromium.launch(launchOptions);
73
+ }
74
+ async render(input) {
75
+ let browser = null;
76
+ try {
77
+ browser = await this.launchBrowser();
78
+ const page = await (await browser.newContext({
79
+ colorScheme: input.darkMode ? "dark" : "light",
80
+ locale: "en-US",
81
+ reducedMotion: "reduce",
82
+ viewport: {
83
+ width: A4_WIDTH,
84
+ height: A4_HEIGHT
85
+ },
86
+ isMobile: false,
87
+ hasTouch: false,
88
+ deviceScaleFactor: 2,
89
+ bypassCSP: true
90
+ })).newPage();
91
+ page.on("console", (msg) => this.logger.debug(`[Browser Log] ${msg.text()}`));
92
+ page.on("requestfailed", (request) => {
93
+ this.logger.error(`[Browser Error] Failed to load resource: ${request.url()} - ${request.failure()?.errorText}`);
94
+ });
95
+ if (input.url) {
96
+ await page.goto(input.url, {
97
+ waitUntil: "load",
98
+ timeout: 6e4
99
+ });
100
+ await page.waitForLoadState("networkidle", { timeout: 6e4 });
101
+ } else if (input.html) {
102
+ await page.setContent(input.html, {
103
+ waitUntil: "load",
104
+ timeout: 6e4
105
+ });
106
+ await page.waitForLoadState("networkidle", { timeout: 6e4 });
107
+ }
108
+ if (input.darkMode) await page.evaluate(() => {
109
+ document.documentElement.classList.add("dark");
110
+ document.body.classList.add("dark");
111
+ });
112
+ if (input.outputType === "pdf") await page.emulateMedia({ media: "print" });
113
+ this.logger.log(`Page content loaded, generating ${input.outputType}...`);
114
+ if (input.outputType === "screenshot") {
115
+ const screenshotBuffer = await page.screenshot({
116
+ fullPage: true,
117
+ type: "png",
118
+ scale: "css",
119
+ animations: "disabled",
120
+ caret: "hide",
121
+ omitBackground: true
122
+ });
123
+ return new Uint8Array(screenshotBuffer);
124
+ }
125
+ const pdfBuffer = await page.pdf({
126
+ format: "A4",
127
+ printBackground: true,
128
+ preferCSSPageSize: true,
129
+ displayHeaderFooter: false,
130
+ outline: false,
131
+ scale: 1,
132
+ margin: {
133
+ top: "0px",
134
+ right: "0px",
135
+ bottom: "0px",
136
+ left: "0px"
137
+ }
138
+ });
139
+ return new Uint8Array(pdfBuffer);
140
+ } catch (error) {
141
+ this.logger.error("Playwright error:", error);
142
+ if (error instanceof Error && error.message.includes("browser")) {
143
+ this.logger.error("\n💡 Troubleshooting tips:");
144
+ this.logger.error(" 1. Make sure Chromium is installed");
145
+ this.logger.error(" 2. Try running: bunx playwright install chromium");
146
+ this.logger.error(" 3. Check system permissions");
147
+ }
148
+ throw error;
149
+ } finally {
150
+ if (browser) await browser.close();
151
+ }
152
+ }
153
+ };
154
+
155
+ //#endregion
156
+ exports.ConsoleLogger = ConsoleLogger;
157
+ exports.PlaywrightPdfService = PlaywrightPdfService;
package/dist/index.mjs ADDED
@@ -0,0 +1,132 @@
1
+ import { access } from "node:fs/promises";
2
+ import { chromium } from "playwright";
3
+
4
+ //#region src/logger.ts
5
+ var ConsoleLogger = class {
6
+ debug(message) {
7
+ if (process.env.NODE_ENV === "development") console.debug(`[PDF Printer] ${message}`);
8
+ }
9
+ log(message) {
10
+ console.log(`[PDF Printer] ${message}`);
11
+ }
12
+ warn(message) {
13
+ console.warn(`[PDF Printer] ${message}`);
14
+ }
15
+ error(message, error) {
16
+ console.error(`[PDF Printer] ${message}`, error);
17
+ }
18
+ };
19
+
20
+ //#endregion
21
+ //#region src/playwright-pdf.service.ts
22
+ const A4_WIDTH = 794;
23
+ const A4_HEIGHT = 1123;
24
+ var PlaywrightPdfService = class {
25
+ constructor(logger = new ConsoleLogger()) {
26
+ this.logger = logger;
27
+ }
28
+ async launchBrowser() {
29
+ const launchOptions = {
30
+ headless: true,
31
+ args: [
32
+ "--no-sandbox",
33
+ "--disable-setuid-sandbox",
34
+ "--disable-web-security",
35
+ "--disable-dev-shm-usage",
36
+ "--disable-blink-features=AutomationControlled",
37
+ "--disable-features=IsolateOrigins,site-per-process"
38
+ ]
39
+ };
40
+ if (process.env.CHROMIUM_EXECUTABLE_PATH) try {
41
+ await access(process.env.CHROMIUM_EXECUTABLE_PATH);
42
+ launchOptions.executablePath = process.env.CHROMIUM_EXECUTABLE_PATH;
43
+ this.logger.debug(`Using system Chromium at: ${process.env.CHROMIUM_EXECUTABLE_PATH}`);
44
+ } catch {
45
+ this.logger.warn(`Chromium path specified but not found: ${process.env.CHROMIUM_EXECUTABLE_PATH}, using Playwright's bundled browser`);
46
+ }
47
+ return chromium.launch(launchOptions);
48
+ }
49
+ async render(input) {
50
+ let browser = null;
51
+ try {
52
+ browser = await this.launchBrowser();
53
+ const page = await (await browser.newContext({
54
+ colorScheme: input.darkMode ? "dark" : "light",
55
+ locale: "en-US",
56
+ reducedMotion: "reduce",
57
+ viewport: {
58
+ width: A4_WIDTH,
59
+ height: A4_HEIGHT
60
+ },
61
+ isMobile: false,
62
+ hasTouch: false,
63
+ deviceScaleFactor: 2,
64
+ bypassCSP: true
65
+ })).newPage();
66
+ page.on("console", (msg) => this.logger.debug(`[Browser Log] ${msg.text()}`));
67
+ page.on("requestfailed", (request) => {
68
+ this.logger.error(`[Browser Error] Failed to load resource: ${request.url()} - ${request.failure()?.errorText}`);
69
+ });
70
+ if (input.url) {
71
+ await page.goto(input.url, {
72
+ waitUntil: "load",
73
+ timeout: 6e4
74
+ });
75
+ await page.waitForLoadState("networkidle", { timeout: 6e4 });
76
+ } else if (input.html) {
77
+ await page.setContent(input.html, {
78
+ waitUntil: "load",
79
+ timeout: 6e4
80
+ });
81
+ await page.waitForLoadState("networkidle", { timeout: 6e4 });
82
+ }
83
+ if (input.darkMode) await page.evaluate(() => {
84
+ document.documentElement.classList.add("dark");
85
+ document.body.classList.add("dark");
86
+ });
87
+ if (input.outputType === "pdf") await page.emulateMedia({ media: "print" });
88
+ this.logger.log(`Page content loaded, generating ${input.outputType}...`);
89
+ if (input.outputType === "screenshot") {
90
+ const screenshotBuffer = await page.screenshot({
91
+ fullPage: true,
92
+ type: "png",
93
+ scale: "css",
94
+ animations: "disabled",
95
+ caret: "hide",
96
+ omitBackground: true
97
+ });
98
+ return new Uint8Array(screenshotBuffer);
99
+ }
100
+ const pdfBuffer = await page.pdf({
101
+ format: "A4",
102
+ printBackground: true,
103
+ preferCSSPageSize: true,
104
+ displayHeaderFooter: false,
105
+ outline: false,
106
+ scale: 1,
107
+ margin: {
108
+ top: "0px",
109
+ right: "0px",
110
+ bottom: "0px",
111
+ left: "0px"
112
+ }
113
+ });
114
+ return new Uint8Array(pdfBuffer);
115
+ } catch (error) {
116
+ this.logger.error("Playwright error:", error);
117
+ if (error instanceof Error && error.message.includes("browser")) {
118
+ this.logger.error("\n💡 Troubleshooting tips:");
119
+ this.logger.error(" 1. Make sure Chromium is installed");
120
+ this.logger.error(" 2. Try running: bunx playwright install chromium");
121
+ this.logger.error(" 3. Check system permissions");
122
+ }
123
+ throw error;
124
+ } finally {
125
+ if (browser) await browser.close();
126
+ }
127
+ }
128
+ };
129
+
130
+ //#endregion
131
+ export { ConsoleLogger, PlaywrightPdfService };
132
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["launchOptions: Parameters<typeof chromium.launch>[0]","browser: Browser | null"],"sources":["../src/logger.ts","../src/playwright-pdf.service.ts"],"sourcesContent":["export interface PdfLogger {\n debug(message: string): void;\n log(message: string): void;\n warn(message: string): void;\n error(message: string, error?: unknown): void;\n}\n\nexport class ConsoleLogger implements PdfLogger {\n debug(message: string): void {\n if (process.env.NODE_ENV === 'development') {\n console.debug(`[PDF Printer] ${message}`);\n }\n }\n\n log(message: string): void {\n console.log(`[PDF Printer] ${message}`);\n }\n\n warn(message: string): void {\n console.warn(`[PDF Printer] ${message}`);\n }\n\n error(message: string, error?: unknown): void {\n console.error(`[PDF Printer] ${message}`, error);\n }\n}\n","import { access } from 'node:fs/promises';\nimport { type Browser, chromium } from 'playwright';\nimport type { PdfLogger } from './logger';\nimport { ConsoleLogger } from './logger';\n\n// A4 dimensions in pixels at 96 DPI (standard web resolution)\n// A4 = 210mm × 297mm = 8.27\" × 11.69\" = 794px × 1123px at 96 DPI\nconst A4_WIDTH = 794;\nconst A4_HEIGHT = 1123;\n\nexport class PlaywrightPdfService {\n private readonly logger: PdfLogger;\n\n constructor(logger: PdfLogger = new ConsoleLogger()) {\n this.logger = logger;\n }\n\n private async launchBrowser(): Promise<Browser> {\n const launchOptions: Parameters<typeof chromium.launch>[0] = {\n headless: true,\n args: [\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-web-security',\n '--disable-dev-shm-usage',\n '--disable-blink-features=AutomationControlled',\n // Bypass CSP (Content Security Policy)\n '--disable-features=IsolateOrigins,site-per-process',\n ],\n };\n\n if (process.env.CHROMIUM_EXECUTABLE_PATH) {\n try {\n await access(process.env.CHROMIUM_EXECUTABLE_PATH);\n launchOptions.executablePath = process.env.CHROMIUM_EXECUTABLE_PATH;\n this.logger.debug(\n `Using system Chromium at: ${process.env.CHROMIUM_EXECUTABLE_PATH}`,\n );\n } catch {\n this.logger.warn(\n `Chromium path specified but not found: ${process.env.CHROMIUM_EXECUTABLE_PATH}, using Playwright's bundled browser`,\n );\n }\n }\n\n return chromium.launch(launchOptions);\n }\n\n async render(input: {\n html?: string;\n url?: string;\n outputType: 'pdf' | 'screenshot';\n darkMode?: boolean;\n }): Promise<Uint8Array> {\n let browser: Browser | null = null;\n\n try {\n browser = await this.launchBrowser();\n\n const context = await browser.newContext({\n colorScheme: input.darkMode ? 'dark' : 'light',\n locale: 'en-US',\n reducedMotion: 'reduce',\n viewport: { width: A4_WIDTH, height: A4_HEIGHT },\n // Mobile and touch settings\n isMobile: false,\n hasTouch: false,\n // Best quality with device scale factor\n deviceScaleFactor: 2, // High DPI for crisp rendering\n // Bypass CSP\n bypassCSP: true,\n });\n\n const page = await context.newPage();\n\n page.on('console', (msg) =>\n this.logger.debug(`[Browser Log] ${msg.text()}`),\n );\n page.on('requestfailed', (request) => {\n this.logger.error(\n `[Browser Error] Failed to load resource: ${request.url()} - ${request.failure()?.errorText}`,\n );\n });\n\n if (input.url) {\n await page.goto(input.url, {\n waitUntil: 'load',\n timeout: 60000,\n });\n // Wait for network to be idle to ensure all resources are loaded\n await page.waitForLoadState('networkidle', { timeout: 60000 });\n } else if (input.html) {\n await page.setContent(input.html, {\n waitUntil: 'load',\n timeout: 60000,\n });\n // Wait for network to be idle (for any resources in the HTML)\n await page.waitForLoadState('networkidle', { timeout: 60000 });\n }\n\n // Apply dark mode class for Theme component system\n // (Playwright's colorScheme already handles @media (prefers-color-scheme: dark))\n if (input.darkMode) {\n await page.evaluate(() => {\n document.documentElement.classList.add('dark');\n document.body.classList.add('dark');\n });\n }\n\n // For PDF generation, emulate print media to apply @media print styles\n if (input.outputType === 'pdf') {\n await page.emulateMedia({ media: 'print' });\n }\n\n this.logger.log(`Page content loaded, generating ${input.outputType}...`);\n\n if (input.outputType === 'screenshot') {\n const screenshotBuffer = await page.screenshot({\n fullPage: true,\n type: 'png',\n scale: 'css',\n animations: 'disabled',\n caret: 'hide',\n omitBackground: true, // Transparent background\n });\n return new Uint8Array(screenshotBuffer);\n }\n const pdfBuffer = await page.pdf({\n format: 'A4',\n printBackground: true,\n preferCSSPageSize: true,\n displayHeaderFooter: false,\n outline: false,\n scale: 1,\n margin: {\n top: '0px',\n right: '0px',\n bottom: '0px',\n left: '0px',\n },\n });\n return new Uint8Array(pdfBuffer);\n } catch (error) {\n this.logger.error('Playwright error:', error);\n if (error instanceof Error && error.message.includes('browser')) {\n this.logger.error('\\n💡 Troubleshooting tips:');\n this.logger.error(' 1. Make sure Chromium is installed');\n this.logger.error(\n ' 2. Try running: bunx playwright install chromium',\n );\n this.logger.error(' 3. Check system permissions');\n }\n throw error;\n } finally {\n if (browser) await browser.close();\n }\n }\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@ahmedrowaihi/pdf-forge-printer",
3
+ "version": "1.0.0-canary.0",
4
+ "description": "Playwright-based PDF and screenshot rendering service",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist/**"
10
+ ],
11
+ "license": "MIT",
12
+ "dependencies": {
13
+ "playwright": "^1.57.0"
14
+ },
15
+ "peerDependencies": {},
16
+ "devDependencies": {
17
+ "@types/node": "22.14.1",
18
+ "typescript": "5.9.3",
19
+ "tsdown": "0.15.12",
20
+ "tsconfig": "1.0.0-canary.0"
21
+ },
22
+ "scripts": {
23
+ "build": "tsdown src/index.ts --format esm,cjs --dts --external playwright",
24
+ "clean": "rm -rf dist"
25
+ }
26
+ }