🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

boxpdf-html

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

boxpdf-html - npm Package Compare versions

Comparing version
1.4.1
to
1.5.0
+24
-2
dist/cli.js

@@ -17,3 +17,18 @@ #!/usr/bin/env node

import { PDFDocument } from "pdf-lib";
import { renderFlow } from "boxpdf";
import { renderFlow, savePdf } from "boxpdf";
// src/password-env.ts
function passwordFromEnvironment(name, environment = process.env) {
if (name === void 0) return void 0;
const password = environment[name];
if (password === void 0) {
throw new Error(`environment variable "${name}" named by --password-env is not set`);
}
if (password.length === 0) {
throw new Error(`environment variable "${name}" named by --password-env is empty`);
}
return password;
}
// src/cli.ts
var help = `boxpdf-html

@@ -40,2 +55,3 @@

--profile Print render phase timings.
--password-env <name> Encrypt with the password stored in this environment variable.
-h, --help Show this help.

@@ -46,2 +62,3 @@

boxpdf-html invoice.html invoice.pdf --css dist/tailwind.css
BOXPDF_PASSWORD='open me' boxpdf-html invoice.html invoice.pdf --password-env BOXPDF_PASSWORD
boxpdf-html invoice.html invoice.pdf --font ./Inter.ttf --bold-font ./Inter-Bold.ttf

@@ -67,2 +84,3 @@ boxpdf-html invoice.html invoice.pdf \\

}
const password = passwordFromEnvironment(options.passwordEnv);
const inputPath = options.input === "-" ? void 0 : resolve(options.input);

@@ -91,3 +109,4 @@ const baseUrl = options.baseUrl ? resolve(options.baseUrl) : inputPath ? dirname(inputPath) : process.cwd();

await renderFlow(pdf, result.nodes, { margin: options.margin, debug: options.debug });
writeFileSync(resolve(options.output), await pdf.save());
const bytes = password === void 0 ? await pdf.save() : await savePdf(pdf, { encryption: { password } });
writeFileSync(resolve(options.output), bytes);
}

@@ -155,2 +174,5 @@ function parseArgs(args) {

break;
case "--password-env":
options.passwordEnv = next();
break;
default:

@@ -157,0 +179,0 @@ fail(`unknown option "${arg}"`);

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { PDFDocument } from \"pdf-lib\";\nimport { renderFlow } from \"boxpdf\";\nimport { fontFamily, htmlToBoxpdf } from \"./index.js\";\nimport { injectCss, loadFaces, loadImages, resolveAssetUrl } from \"./render-file.js\";\n\ninterface CliOptions {\n input?: string;\n output?: string;\n css: string[];\n baseUrl?: string;\n font?: string;\n boldFont?: string;\n italicFont?: string;\n boldItalicFont?: string;\n families: string[];\n width?: number;\n margin: number;\n debug: boolean;\n unsupportedCss: boolean;\n profile: boolean;\n}\n\nconst help = `boxpdf-html\n\nUsage:\n boxpdf-html <input.html> <output.pdf> [options]\n boxpdf-html - <output.pdf> [options]\n boxpdf-html mcp # start the MCP server (stdio)\n\nOptions:\n --css <file> Inject an extra stylesheet before rendering. Repeatable.\n --base-url <dir-or-url> Base path for relative images and background URLs.\n --font <file> Default normal TTF/OTF font.\n --bold-font <file> Default bold TTF/OTF font.\n --italic-font <file> Default italic TTF/OTF font.\n --bold-italic-font <file> Default bold italic TTF/OTF font.\n --font-family <mapping> Map a CSS family to loaded font files. Repeatable.\n Example: Inter=normal:Inter.ttf,bold:Inter-Bold.ttf\n --width <pt> CSS containing block width in PDF points.\n --margin <pt> Page margin for renderFlow. Default: 40.\n --debug Draw boxpdf debug overlays.\n --unsupported-css Print aggregated unsupported CSS diagnostics.\n --profile Print render phase timings.\n -h, --help Show this help.\n\nExamples:\n boxpdf-html invoice.html invoice.pdf\n boxpdf-html invoice.html invoice.pdf --css dist/tailwind.css\n boxpdf-html invoice.html invoice.pdf --font ./Inter.ttf --bold-font ./Inter-Bold.ttf\n boxpdf-html invoice.html invoice.pdf \\\\\n --font-family 'Inter=normal:Inter.ttf,bold:Inter-Bold.ttf,italic:Inter-Italic.ttf'\n`;\n\nmain().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`boxpdf-html: ${message}`);\n process.exit(1);\n});\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n if (argv[0] === \"mcp\") {\n const { startMcpServer } = await import(\"./mcp.js\");\n startMcpServer();\n return;\n }\n\n const options = parseArgs(argv);\n if (!options.input || !options.output) {\n printHelpAndExit(options.input || options.output ? 1 : 0);\n }\n\n const inputPath = options.input === \"-\" ? undefined : resolve(options.input);\n const baseUrl = options.baseUrl ? resolve(options.baseUrl) : inputPath ? dirname(inputPath) : process.cwd();\n const html = injectCss(readInput(options.input), options.css.map((path) => readFileSync(resolve(path), \"utf8\")));\n const pdf = await PDFDocument.create();\n const faces = await loadFaces(pdf, options, baseUrl);\n const images = await loadImages(pdf, html, baseUrl, {\n allowRemote: true,\n onWarn: (message) => console.warn(`boxpdf-html: ${message}`)\n });\n\n const result = htmlToBoxpdf(html, {\n font: faces.normal,\n boldFont: faces.bold,\n italicFont: faces.italic,\n resolveFont: fontFamily(faces.families),\n resolveImage: ({ url }) => images.get(resolveAssetUrl(url, baseUrl)),\n baseUrl,\n width: options.width ?? Math.max(0, 612 - options.margin * 2),\n diagnostics: options.unsupportedCss ? { unsupportedCss: true, sampleLimit: 5 } : undefined,\n profile: options.profile ? (event) => console.error(`[profile] ${event.phase} ${event.elapsedMs.toFixed(1)}ms`) : undefined\n });\n\n for (const warning of result.warnings) console.warn(`boxpdf-html: ${warning}`);\n if (options.unsupportedCss) printUnsupportedCss(result.diagnostics?.unsupportedCss ?? []);\n\n await renderFlow(pdf, result.nodes, { margin: options.margin, debug: options.debug });\n writeFileSync(resolve(options.output), await pdf.save());\n}\n\nfunction parseArgs(args: string[]): CliOptions {\n const options: CliOptions = {\n css: [],\n families: [],\n margin: 40,\n debug: false,\n unsupportedCss: false,\n profile: false\n };\n\n for (let i = 0; i < args.length; i += 1) {\n const arg = args[i]!;\n if (arg === \"-h\" || arg === \"--help\" || arg === \"help\") printHelpAndExit(0);\n if (!arg.startsWith(\"-\") || arg === \"-\") {\n if (!options.input) options.input = arg;\n else if (!options.output) options.output = arg;\n else fail(`unexpected argument \"${arg}\"`);\n continue;\n }\n\n const next = (): string => {\n const value = args[i + 1];\n if (!value) fail(`${arg} requires a value`);\n i += 1;\n return value;\n };\n\n switch (arg) {\n case \"--css\":\n options.css.push(next());\n break;\n case \"--base-url\":\n options.baseUrl = next();\n break;\n case \"--font\":\n options.font = next();\n break;\n case \"--bold-font\":\n options.boldFont = next();\n break;\n case \"--italic-font\":\n options.italicFont = next();\n break;\n case \"--bold-italic-font\":\n options.boldItalicFont = next();\n break;\n case \"--font-family\":\n options.families.push(next());\n break;\n case \"--width\":\n options.width = parseNumber(next(), arg);\n break;\n case \"--margin\":\n options.margin = parseNumber(next(), arg);\n break;\n case \"--debug\":\n options.debug = true;\n break;\n case \"--unsupported-css\":\n options.unsupportedCss = true;\n break;\n case \"--profile\":\n options.profile = true;\n break;\n default:\n fail(`unknown option \"${arg}\"`);\n }\n }\n\n return options;\n}\n\nfunction readInput(input: string): string {\n if (input === \"-\") return readFileSync(0, \"utf8\");\n return readFileSync(resolve(input), \"utf8\");\n}\n\nfunction printUnsupportedCss(items: Array<{ property: string; value: string; count: number; samples?: string[] }>): void {\n if (items.length === 0) return;\n console.error(\"Unsupported CSS:\");\n for (const item of items) {\n console.error(`- ${item.property}: ${item.value} (${item.count})`);\n for (const sample of item.samples ?? []) console.error(` ${sample}`);\n }\n}\n\nfunction parseNumber(value: string, option: string): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < 0) fail(`${option} must be a non-negative number`);\n return parsed;\n}\n\nfunction printHelpAndExit(code: number): never {\n console.log(help);\n process.exit(code);\n}\n\nfunction fail(message: string): never {\n console.error(`boxpdf-html: ${message}`);\n process.exit(1);\n}\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/cli.ts","../src/password-env.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { PDFDocument } from \"pdf-lib\";\nimport { renderFlow, savePdf } from \"boxpdf\";\nimport { fontFamily, htmlToBoxpdf } from \"./index.js\";\nimport { passwordFromEnvironment } from \"./password-env.js\";\nimport { injectCss, loadFaces, loadImages, resolveAssetUrl } from \"./render-file.js\";\n\ninterface CliOptions {\n input?: string;\n output?: string;\n css: string[];\n baseUrl?: string;\n font?: string;\n boldFont?: string;\n italicFont?: string;\n boldItalicFont?: string;\n families: string[];\n width?: number;\n margin: number;\n debug: boolean;\n unsupportedCss: boolean;\n profile: boolean;\n passwordEnv?: string;\n}\n\nconst help = `boxpdf-html\n\nUsage:\n boxpdf-html <input.html> <output.pdf> [options]\n boxpdf-html - <output.pdf> [options]\n boxpdf-html mcp # start the MCP server (stdio)\n\nOptions:\n --css <file> Inject an extra stylesheet before rendering. Repeatable.\n --base-url <dir-or-url> Base path for relative images and background URLs.\n --font <file> Default normal TTF/OTF font.\n --bold-font <file> Default bold TTF/OTF font.\n --italic-font <file> Default italic TTF/OTF font.\n --bold-italic-font <file> Default bold italic TTF/OTF font.\n --font-family <mapping> Map a CSS family to loaded font files. Repeatable.\n Example: Inter=normal:Inter.ttf,bold:Inter-Bold.ttf\n --width <pt> CSS containing block width in PDF points.\n --margin <pt> Page margin for renderFlow. Default: 40.\n --debug Draw boxpdf debug overlays.\n --unsupported-css Print aggregated unsupported CSS diagnostics.\n --profile Print render phase timings.\n --password-env <name> Encrypt with the password stored in this environment variable.\n -h, --help Show this help.\n\nExamples:\n boxpdf-html invoice.html invoice.pdf\n boxpdf-html invoice.html invoice.pdf --css dist/tailwind.css\n BOXPDF_PASSWORD='open me' boxpdf-html invoice.html invoice.pdf --password-env BOXPDF_PASSWORD\n boxpdf-html invoice.html invoice.pdf --font ./Inter.ttf --bold-font ./Inter-Bold.ttf\n boxpdf-html invoice.html invoice.pdf \\\\\n --font-family 'Inter=normal:Inter.ttf,bold:Inter-Bold.ttf,italic:Inter-Italic.ttf'\n`;\n\nmain().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`boxpdf-html: ${message}`);\n process.exit(1);\n});\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n if (argv[0] === \"mcp\") {\n const { startMcpServer } = await import(\"./mcp.js\");\n startMcpServer();\n return;\n }\n\n const options = parseArgs(argv);\n if (!options.input || !options.output) {\n printHelpAndExit(options.input || options.output ? 1 : 0);\n }\n const password = passwordFromEnvironment(options.passwordEnv);\n\n const inputPath = options.input === \"-\" ? undefined : resolve(options.input);\n const baseUrl = options.baseUrl ? resolve(options.baseUrl) : inputPath ? dirname(inputPath) : process.cwd();\n const html = injectCss(readInput(options.input), options.css.map((path) => readFileSync(resolve(path), \"utf8\")));\n const pdf = await PDFDocument.create();\n const faces = await loadFaces(pdf, options, baseUrl);\n const images = await loadImages(pdf, html, baseUrl, {\n allowRemote: true,\n onWarn: (message) => console.warn(`boxpdf-html: ${message}`)\n });\n\n const result = htmlToBoxpdf(html, {\n font: faces.normal,\n boldFont: faces.bold,\n italicFont: faces.italic,\n resolveFont: fontFamily(faces.families),\n resolveImage: ({ url }) => images.get(resolveAssetUrl(url, baseUrl)),\n baseUrl,\n width: options.width ?? Math.max(0, 612 - options.margin * 2),\n diagnostics: options.unsupportedCss ? { unsupportedCss: true, sampleLimit: 5 } : undefined,\n profile: options.profile ? (event) => console.error(`[profile] ${event.phase} ${event.elapsedMs.toFixed(1)}ms`) : undefined\n });\n\n for (const warning of result.warnings) console.warn(`boxpdf-html: ${warning}`);\n if (options.unsupportedCss) printUnsupportedCss(result.diagnostics?.unsupportedCss ?? []);\n\n await renderFlow(pdf, result.nodes, { margin: options.margin, debug: options.debug });\n const bytes = password === undefined\n ? await pdf.save()\n : await savePdf(pdf, { encryption: { password } });\n writeFileSync(resolve(options.output), bytes);\n}\n\nfunction parseArgs(args: string[]): CliOptions {\n const options: CliOptions = {\n css: [],\n families: [],\n margin: 40,\n debug: false,\n unsupportedCss: false,\n profile: false\n };\n\n for (let i = 0; i < args.length; i += 1) {\n const arg = args[i]!;\n if (arg === \"-h\" || arg === \"--help\" || arg === \"help\") printHelpAndExit(0);\n if (!arg.startsWith(\"-\") || arg === \"-\") {\n if (!options.input) options.input = arg;\n else if (!options.output) options.output = arg;\n else fail(`unexpected argument \"${arg}\"`);\n continue;\n }\n\n const next = (): string => {\n const value = args[i + 1];\n if (!value) fail(`${arg} requires a value`);\n i += 1;\n return value;\n };\n\n switch (arg) {\n case \"--css\":\n options.css.push(next());\n break;\n case \"--base-url\":\n options.baseUrl = next();\n break;\n case \"--font\":\n options.font = next();\n break;\n case \"--bold-font\":\n options.boldFont = next();\n break;\n case \"--italic-font\":\n options.italicFont = next();\n break;\n case \"--bold-italic-font\":\n options.boldItalicFont = next();\n break;\n case \"--font-family\":\n options.families.push(next());\n break;\n case \"--width\":\n options.width = parseNumber(next(), arg);\n break;\n case \"--margin\":\n options.margin = parseNumber(next(), arg);\n break;\n case \"--debug\":\n options.debug = true;\n break;\n case \"--unsupported-css\":\n options.unsupportedCss = true;\n break;\n case \"--profile\":\n options.profile = true;\n break;\n case \"--password-env\":\n options.passwordEnv = next();\n break;\n default:\n fail(`unknown option \"${arg}\"`);\n }\n }\n\n return options;\n}\n\nfunction readInput(input: string): string {\n if (input === \"-\") return readFileSync(0, \"utf8\");\n return readFileSync(resolve(input), \"utf8\");\n}\n\nfunction printUnsupportedCss(items: Array<{ property: string; value: string; count: number; samples?: string[] }>): void {\n if (items.length === 0) return;\n console.error(\"Unsupported CSS:\");\n for (const item of items) {\n console.error(`- ${item.property}: ${item.value} (${item.count})`);\n for (const sample of item.samples ?? []) console.error(` ${sample}`);\n }\n}\n\nfunction parseNumber(value: string, option: string): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < 0) fail(`${option} must be a non-negative number`);\n return parsed;\n}\n\nfunction printHelpAndExit(code: number): never {\n console.log(help);\n process.exit(code);\n}\n\nfunction fail(message: string): never {\n console.error(`boxpdf-html: ${message}`);\n process.exit(1);\n}\n","export function passwordFromEnvironment(\n name: string | undefined,\n environment: NodeJS.ProcessEnv = process.env\n): string | undefined {\n if (name === undefined) return undefined;\n const password = environment[name];\n if (password === undefined) {\n throw new Error(`environment variable \"${name}\" named by --password-env is not set`);\n }\n if (password.length === 0) {\n throw new Error(`environment variable \"${name}\" named by --password-env is empty`);\n }\n return password;\n}\n"],"mappings":"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","names":[]}
{
"name": "boxpdf-html",
"version": "1.4.1",
"version": "1.5.0",
"mcpName": "io.github.earonesty/boxpdf-html",

@@ -46,3 +46,3 @@ "description": "Readable HTML-to-PDF translator built on boxpdf.",

"dependencies": {
"boxpdf": "^1.10.0",
"boxpdf": "^1.11.0",
"css-tree": "^3.1.0",

@@ -62,3 +62,3 @@ "parse5": "^8.0.0",

"engines": {
"node": ">=18"
"node": ">=20"
},

@@ -65,0 +65,0 @@ "publishConfig": {

@@ -24,2 +24,13 @@ # boxpdf-html

With PDF 2.0 AES-256 password encryption:
```sh
BOXPDF_PASSWORD='open me' \
npx boxpdf-html invoice.html invoice.pdf --password-env BOXPDF_PASSWORD
```
`--password-env` accepts an environment-variable name. The variable must be
set to a non-empty password. The password value is never accepted as a command
argument, which keeps it out of the command line and process listing.
With custom fonts and local images:

@@ -41,2 +52,3 @@

boxpdf-html input.html output.pdf --base-url ./public
boxpdf-html input.html output.pdf --password-env BOXPDF_PASSWORD
boxpdf-html input.html output.pdf --debug

@@ -43,0 +55,0 @@ boxpdf-html input.html output.pdf --unsupported-css

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display