feat: complete OpenAPI docs with all Puppeteer PDF options
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
- Add scale, pageRanges, preferCSSPageSize, width, height to PdfOptions - Add headerTemplate, footerTemplate, displayHeaderFooter to docs - Pass all options through routes to browser service for HTML, Markdown, and URL endpoints - Export PdfRenderOptions interface for type reuse - Bump version to 0.4.5
This commit is contained in:
parent
f332d425ec
commit
1545df9a7b
5 changed files with 111 additions and 21 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "docfast-api",
|
"name": "docfast-api",
|
||||||
"version": "0.4.3",
|
"version": "0.4.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "docfast-api",
|
"name": "docfast-api",
|
||||||
"version": "0.4.3",
|
"version": "0.4.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"compression": "^1.8.1",
|
"compression": "^1.8.1",
|
||||||
"express": "^4.21.0",
|
"express": "^4.21.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "docfast-api",
|
"name": "docfast-api",
|
||||||
"version": "0.4.4",
|
"version": "0.4.5",
|
||||||
"description": "Markdown/HTML to PDF API with built-in invoice templates",
|
"description": "Markdown/HTML to PDF API with built-in invoice templates",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,14 @@ interface ConvertBody {
|
||||||
margin?: { top?: string; right?: string; bottom?: string; left?: string };
|
margin?: { top?: string; right?: string; bottom?: string; left?: string };
|
||||||
printBackground?: boolean;
|
printBackground?: boolean;
|
||||||
filename?: string;
|
filename?: string;
|
||||||
|
headerTemplate?: string;
|
||||||
|
footerTemplate?: string;
|
||||||
|
displayHeaderFooter?: boolean;
|
||||||
|
scale?: number;
|
||||||
|
pageRanges?: string;
|
||||||
|
preferCSSPageSize?: boolean;
|
||||||
|
width?: string;
|
||||||
|
height?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -131,6 +139,14 @@ convertRouter.post("/html", async (req: Request & { acquirePdfSlot?: () => Promi
|
||||||
landscape: body.landscape,
|
landscape: body.landscape,
|
||||||
margin: body.margin,
|
margin: body.margin,
|
||||||
printBackground: body.printBackground,
|
printBackground: body.printBackground,
|
||||||
|
headerTemplate: body.headerTemplate,
|
||||||
|
footerTemplate: body.footerTemplate,
|
||||||
|
displayHeaderFooter: body.displayHeaderFooter,
|
||||||
|
scale: body.scale,
|
||||||
|
pageRanges: body.pageRanges,
|
||||||
|
preferCSSPageSize: body.preferCSSPageSize,
|
||||||
|
width: body.width,
|
||||||
|
height: body.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
const filename = sanitizeFilename(body.filename || "document.pdf");
|
const filename = sanitizeFilename(body.filename || "document.pdf");
|
||||||
|
|
@ -228,6 +244,14 @@ convertRouter.post("/markdown", async (req: Request & { acquirePdfSlot?: () => P
|
||||||
landscape: body.landscape,
|
landscape: body.landscape,
|
||||||
margin: body.margin,
|
margin: body.margin,
|
||||||
printBackground: body.printBackground,
|
printBackground: body.printBackground,
|
||||||
|
headerTemplate: body.headerTemplate,
|
||||||
|
footerTemplate: body.footerTemplate,
|
||||||
|
displayHeaderFooter: body.displayHeaderFooter,
|
||||||
|
scale: body.scale,
|
||||||
|
pageRanges: body.pageRanges,
|
||||||
|
preferCSSPageSize: body.preferCSSPageSize,
|
||||||
|
width: body.width,
|
||||||
|
height: body.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
const filename = sanitizeFilename(body.filename || "document.pdf");
|
const filename = sanitizeFilename(body.filename || "document.pdf");
|
||||||
|
|
@ -310,7 +334,7 @@ convertRouter.post("/url", async (req: Request & { acquirePdfSlot?: () => Promis
|
||||||
res.status(415).json({ error: "Unsupported Content-Type. Use application/json." });
|
res.status(415).json({ error: "Unsupported Content-Type. Use application/json." });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const body = req.body as { url?: string; format?: string; landscape?: boolean; margin?: any; printBackground?: boolean; waitUntil?: string; filename?: string };
|
const body = req.body as { url?: string; format?: string; landscape?: boolean; margin?: any; printBackground?: boolean; waitUntil?: string; filename?: string; headerTemplate?: string; footerTemplate?: string; displayHeaderFooter?: boolean; scale?: number; pageRanges?: string; preferCSSPageSize?: boolean; width?: string; height?: string };
|
||||||
|
|
||||||
if (!body.url) {
|
if (!body.url) {
|
||||||
res.status(400).json({ error: "Missing 'url' field" });
|
res.status(400).json({ error: "Missing 'url' field" });
|
||||||
|
|
@ -355,6 +379,14 @@ convertRouter.post("/url", async (req: Request & { acquirePdfSlot?: () => Promis
|
||||||
landscape: body.landscape,
|
landscape: body.landscape,
|
||||||
margin: body.margin,
|
margin: body.margin,
|
||||||
printBackground: body.printBackground,
|
printBackground: body.printBackground,
|
||||||
|
headerTemplate: body.headerTemplate,
|
||||||
|
footerTemplate: body.footerTemplate,
|
||||||
|
displayHeaderFooter: body.displayHeaderFooter,
|
||||||
|
scale: body.scale,
|
||||||
|
pageRanges: body.pageRanges,
|
||||||
|
preferCSSPageSize: body.preferCSSPageSize,
|
||||||
|
width: body.width,
|
||||||
|
height: body.height,
|
||||||
waitUntil: body.waitUntil,
|
waitUntil: body.waitUntil,
|
||||||
hostResolverRules: `MAP ${parsed.hostname} ${resolvedAddress}`,
|
hostResolverRules: `MAP ${parsed.hostname} ${resolvedAddress}`,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -218,9 +218,7 @@ export async function closeBrowser(): Promise<void> {
|
||||||
instances.length = 0;
|
instances.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function renderPdf(
|
export interface PdfRenderOptions {
|
||||||
html: string,
|
|
||||||
options: {
|
|
||||||
format?: string;
|
format?: string;
|
||||||
landscape?: boolean;
|
landscape?: boolean;
|
||||||
margin?: { top?: string; right?: string; bottom?: string; left?: string };
|
margin?: { top?: string; right?: string; bottom?: string; left?: string };
|
||||||
|
|
@ -228,7 +226,16 @@ export async function renderPdf(
|
||||||
headerTemplate?: string;
|
headerTemplate?: string;
|
||||||
footerTemplate?: string;
|
footerTemplate?: string;
|
||||||
displayHeaderFooter?: boolean;
|
displayHeaderFooter?: boolean;
|
||||||
} = {}
|
scale?: number;
|
||||||
|
pageRanges?: string;
|
||||||
|
preferCSSPageSize?: boolean;
|
||||||
|
width?: string;
|
||||||
|
height?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function renderPdf(
|
||||||
|
html: string,
|
||||||
|
options: PdfRenderOptions = {}
|
||||||
): Promise<Buffer> {
|
): Promise<Buffer> {
|
||||||
const { page, instance } = await acquirePage();
|
const { page, instance } = await acquirePage();
|
||||||
try {
|
try {
|
||||||
|
|
@ -245,6 +252,11 @@ export async function renderPdf(
|
||||||
headerTemplate: options.headerTemplate,
|
headerTemplate: options.headerTemplate,
|
||||||
footerTemplate: options.footerTemplate,
|
footerTemplate: options.footerTemplate,
|
||||||
displayHeaderFooter: options.displayHeaderFooter || false,
|
displayHeaderFooter: options.displayHeaderFooter || false,
|
||||||
|
...(options.scale !== undefined && { scale: options.scale }),
|
||||||
|
...(options.pageRanges && { pageRanges: options.pageRanges }),
|
||||||
|
...(options.preferCSSPageSize !== undefined && { preferCSSPageSize: options.preferCSSPageSize }),
|
||||||
|
...(options.width && { width: options.width }),
|
||||||
|
...(options.height && { height: options.height }),
|
||||||
});
|
});
|
||||||
return Buffer.from(pdf);
|
return Buffer.from(pdf);
|
||||||
})(),
|
})(),
|
||||||
|
|
@ -260,11 +272,7 @@ export async function renderPdf(
|
||||||
|
|
||||||
export async function renderUrlPdf(
|
export async function renderUrlPdf(
|
||||||
url: string,
|
url: string,
|
||||||
options: {
|
options: PdfRenderOptions & {
|
||||||
format?: string;
|
|
||||||
landscape?: boolean;
|
|
||||||
margin?: { top?: string; right?: string; bottom?: string; left?: string };
|
|
||||||
printBackground?: boolean;
|
|
||||||
waitUntil?: string;
|
waitUntil?: string;
|
||||||
hostResolverRules?: string;
|
hostResolverRules?: string;
|
||||||
} = {}
|
} = {}
|
||||||
|
|
@ -316,6 +324,14 @@ export async function renderUrlPdf(
|
||||||
landscape: options.landscape || false,
|
landscape: options.landscape || false,
|
||||||
printBackground: options.printBackground !== false,
|
printBackground: options.printBackground !== false,
|
||||||
margin: options.margin || { top: "0", right: "0", bottom: "0", left: "0" },
|
margin: options.margin || { top: "0", right: "0", bottom: "0", left: "0" },
|
||||||
|
...(options.headerTemplate && { headerTemplate: options.headerTemplate }),
|
||||||
|
...(options.footerTemplate && { footerTemplate: options.footerTemplate }),
|
||||||
|
...(options.displayHeaderFooter !== undefined && { displayHeaderFooter: options.displayHeaderFooter }),
|
||||||
|
...(options.scale !== undefined && { scale: options.scale }),
|
||||||
|
...(options.pageRanges && { pageRanges: options.pageRanges }),
|
||||||
|
...(options.preferCSSPageSize !== undefined && { preferCSSPageSize: options.preferCSSPageSize }),
|
||||||
|
...(options.width && { width: options.width }),
|
||||||
|
...(options.height && { height: options.height }),
|
||||||
});
|
});
|
||||||
return Buffer.from(pdf);
|
return Buffer.from(pdf);
|
||||||
})(),
|
})(),
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ const options: swaggerJsdoc.Options = {
|
||||||
type: "string",
|
type: "string",
|
||||||
enum: ["A4", "Letter", "Legal", "A3", "A5", "Tabloid"],
|
enum: ["A4", "Letter", "Legal", "A3", "A5", "Tabloid"],
|
||||||
default: "A4",
|
default: "A4",
|
||||||
description: "Page size",
|
description: "Page size. Ignored if width/height are set.",
|
||||||
},
|
},
|
||||||
landscape: {
|
landscape: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
|
|
@ -58,6 +58,7 @@ const options: swaggerJsdoc.Options = {
|
||||||
},
|
},
|
||||||
margin: {
|
margin: {
|
||||||
type: "object",
|
type: "object",
|
||||||
|
description: "Page margins. Accepts CSS units (e.g. '20mm', '1in', '72px').",
|
||||||
properties: {
|
properties: {
|
||||||
top: { type: "string", example: "20mm" },
|
top: { type: "string", example: "20mm" },
|
||||||
bottom: { type: "string", example: "20mm" },
|
bottom: { type: "string", example: "20mm" },
|
||||||
|
|
@ -68,12 +69,53 @@ const options: swaggerJsdoc.Options = {
|
||||||
printBackground: {
|
printBackground: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
default: true,
|
default: true,
|
||||||
description: "Print background graphics",
|
description: "Print background graphics and colors",
|
||||||
},
|
},
|
||||||
filename: {
|
filename: {
|
||||||
type: "string",
|
type: "string",
|
||||||
default: "document.pdf",
|
default: "document.pdf",
|
||||||
description: "Suggested filename for the PDF",
|
description: "Suggested filename for the PDF download",
|
||||||
|
},
|
||||||
|
headerTemplate: {
|
||||||
|
type: "string",
|
||||||
|
description: "HTML template for the page header. Requires displayHeaderFooter: true. Use these CSS classes for dynamic values: date, title, url, pageNumber, totalPages. Example: '<span class=\"pageNumber\"></span> / <span class=\"totalPages\"></span>'",
|
||||||
|
},
|
||||||
|
footerTemplate: {
|
||||||
|
type: "string",
|
||||||
|
description: "HTML template for the page footer. Requires displayHeaderFooter: true. Supports the same CSS classes as headerTemplate.",
|
||||||
|
},
|
||||||
|
displayHeaderFooter: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
description: "Whether to show header and footer templates. Must be true for headerTemplate/footerTemplate to render.",
|
||||||
|
},
|
||||||
|
scale: {
|
||||||
|
type: "number",
|
||||||
|
minimum: 0.1,
|
||||||
|
maximum: 2,
|
||||||
|
default: 1,
|
||||||
|
description: "Scale of the webpage rendering. 1 = 100%, 0.5 = 50%, 2 = 200%.",
|
||||||
|
example: 1,
|
||||||
|
},
|
||||||
|
pageRanges: {
|
||||||
|
type: "string",
|
||||||
|
description: "Paper ranges to print, e.g. '1-5', '1,3,5', '2-4,6'. Empty string means all pages.",
|
||||||
|
example: "1-3",
|
||||||
|
},
|
||||||
|
preferCSSPageSize: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
description: "Give any CSS @page size declared in the page priority over the format option.",
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: "string",
|
||||||
|
description: "Paper width with units. Overrides format. Accepts CSS units (e.g. '10in', '210mm', '8.5in').",
|
||||||
|
example: "8.5in",
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: "string",
|
||||||
|
description: "Paper height with units. Overrides format. Accepts CSS units (e.g. '11in', '297mm').",
|
||||||
|
example: "11in",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue