pdfn 0.4.0 → 0.4.1
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 +0 -2
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,14 +69,12 @@ npx pdfn add contract # Add contract template
|
|
|
69
69
|
npx pdfn add ticket # Add event ticket
|
|
70
70
|
npx pdfn add poster # Add poster template
|
|
71
71
|
npx pdfn add --list # Show all templates
|
|
72
|
-
npx pdfn add invoice --output ./src/templates
|
|
73
72
|
```
|
|
74
73
|
|
|
75
74
|
| Option | Default | Description |
|
|
76
75
|
|--------|---------|-------------|
|
|
77
76
|
| `--inline` | ✓ | Use inline styles (default, no extra dependencies) |
|
|
78
77
|
| `--tailwind` | | Use Tailwind CSS classes (requires `@pdfn/tailwind`) |
|
|
79
|
-
| `--output` | `./pdfn-templates` | Output directory |
|
|
80
78
|
| `--force` | | Overwrite existing files |
|
|
81
79
|
|
|
82
80
|
| Template | Description | Page Size |
|
package/dist/cli.js
CHANGED
|
@@ -2191,8 +2191,9 @@ function isTailwindInstalled(cwd) {
|
|
|
2191
2191
|
const tailwindPath = join2(cwd, "node_modules", "@pdfn", "tailwind");
|
|
2192
2192
|
return existsSync3(tailwindPath);
|
|
2193
2193
|
}
|
|
2194
|
-
var addCommand = new Command3("add").description("Add a starter template to your project").argument("[template]", "Template name (e.g., invoice, letter, contract)").option("--list", "List available templates").option("--tailwind", "Use Tailwind CSS styling (requires @pdfn/tailwind)").option("--inline", "Use inline styles (default)").option("--
|
|
2194
|
+
var addCommand = new Command3("add").description("Add a starter template to your project").argument("[template]", "Template name (e.g., invoice, letter, contract)").option("--list", "List available templates").option("--tailwind", "Use Tailwind CSS styling (requires @pdfn/tailwind)").option("--inline", "Use inline styles (default)").option("--force", "Overwrite existing files").action(async (template, options) => {
|
|
2195
2195
|
const cwd = process.cwd();
|
|
2196
|
+
const outputDir = "./pdfn-templates";
|
|
2196
2197
|
if (options.list || !template) {
|
|
2197
2198
|
console.log(chalk2.bold("\nAvailable templates:\n"));
|
|
2198
2199
|
for (const [id, info] of Object.entries(TEMPLATES)) {
|
|
@@ -2225,7 +2226,6 @@ Error: Unknown template "${template}"`));
|
|
|
2225
2226
|
}
|
|
2226
2227
|
const templatesDir = getTemplatesDir(style);
|
|
2227
2228
|
const sourceFile = join2(templatesDir, `${template}.tsx`);
|
|
2228
|
-
const outputDir = options.output;
|
|
2229
2229
|
const outputFile = join2(outputDir, `${template}.tsx`);
|
|
2230
2230
|
if (!existsSync3(sourceFile)) {
|
|
2231
2231
|
console.error(chalk2.red(`
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/dev.ts","../src/server/base.ts","../src/server/browser.ts","../src/utils/debug.ts","../src/server/pdf.ts","../src/server/routes.ts","../src/utils/env.ts","../src/commands/serve.ts","../src/utils/logger.ts","../src/server/index.ts","../src/commands/add.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { devCommand } from \"./commands/dev.js\";\nimport { serveCommand } from \"./commands/serve.js\";\nimport { addCommand } from \"./commands/add.js\";\n\nconst program = new Command()\n .name(\"pdfn\")\n .description(\"PDFN CLI - PDF generation from React components\")\n .version(\"0.0.1-alpha.1\");\n\nprogram.addCommand(devCommand);\nprogram.addCommand(serveCommand);\nprogram.addCommand(addCommand);\n\nprogram.parse();\n","import { Command } from \"commander\";\nimport { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport type { Request, Response } from \"express\";\nimport { createServer as createViteServer } from \"vite\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport chokidar from \"chokidar\";\nimport { createServer as createHttpServer } from \"http\";\nimport { spawn } from \"child_process\";\nimport puppeteer from \"puppeteer\";\nimport { createBaseServer } from \"../server/base\";\nimport { generatePdf } from \"../server/pdf\";\nimport type { DebugOptions } from \"@pdfn/react\";\nimport { pdfnTailwind } from \"@pdfn/vite\";\nimport chalk from \"chalk\";\nimport { loadEnv } from \"../utils/env\";\n\ninterface TemplateInfo {\n id: string;\n name: string;\n file: string;\n path: string;\n sampleData?: Record<string, unknown>;\n}\n\n/**\n * Standardized templates directory (convention over configuration)\n */\nconst TEMPLATES_DIR = \"./pdfn-templates\";\n\ninterface DevServerOptions {\n port: number;\n open: boolean;\n mode: string;\n}\n\nasync function scanTemplates(templatesDir: string): Promise<TemplateInfo[]> {\n if (!existsSync(templatesDir)) {\n return [];\n }\n\n // Try to load config file with sample data\n let configData: Record<string, Record<string, unknown>> = {};\n const configPaths = [\n join(process.cwd(), \"src\", \"config\", \"templates.json\"),\n join(process.cwd(), \"templates.json\"),\n join(templatesDir, \"templates.json\"),\n ];\n\n for (const configPath of configPaths) {\n if (existsSync(configPath)) {\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (config.templates && Array.isArray(config.templates)) {\n for (const t of config.templates) {\n if (t.id && t.sampleData) {\n configData[t.id] = t.sampleData;\n }\n }\n }\n break;\n } catch {\n // Ignore config parse errors\n }\n }\n }\n\n const files = readdirSync(templatesDir).filter((f) => f.endsWith(\".tsx\"));\n\n // Filter to only include files that look like templates\n // (have \"export default function\" or similar patterns)\n const templates: TemplateInfo[] = [];\n\n for (const file of files) {\n const id = file.replace(\".tsx\", \"\");\n const filePath = join(templatesDir, file);\n\n // Quick check: read file and look for default export pattern\n try {\n const content = readFileSync(filePath, \"utf-8\");\n // Must have a default export that looks like a component\n if (!content.includes(\"export default\") || !content.includes(\"function\")) {\n continue;\n }\n // Skip files that are clearly not templates (no Document/Page imports)\n if (!content.includes(\"Document\") && !content.includes(\"Page\")) {\n continue;\n }\n } catch {\n continue;\n }\n\n // Convert kebab/snake case to Title Case\n const name = id\n .split(/[-_]/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \");\n\n templates.push({\n id,\n name,\n file,\n path: filePath,\n sampleData: configData[id],\n });\n }\n\n return templates;\n}\n\nfunction createPreviewHTML(templates: TemplateInfo[], activeTemplate: string | null): string {\n const templateList = templates\n .map(\n (t) => `\n <button\n class=\"template-btn ${t.id === activeTemplate ? \"active\" : \"\"}\"\n data-template=\"${t.id}\"\n data-file=\"${t.file}\"\n >\n <span class=\"template-name\">${t.name}</span>\n </button>\n `\n )\n .join(\"\");\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>PDFN Dev Server</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n :root {\n --primary: #22d3ee;\n --primary-hover: #06b6d4;\n --bg: #0a0a0a;\n --surface-1: #111;\n --surface-2: #1a1a1a;\n --border: #222;\n --text: #fafafa;\n --text-muted: #666;\n --text-secondary: #888;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--bg);\n color: var(--text);\n min-height: 100vh;\n }\n\n .header {\n background: var(--surface-1);\n border-bottom: 1px solid var(--border);\n padding: 12px 24px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .logo {\n font-size: 20px;\n font-weight: 800;\n letter-spacing: -0.5px;\n }\n\n .logo span { color: var(--primary); }\n\n .status {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #22c55e;\n }\n\n .status-dot.disconnected { background: #ef4444; }\n\n .container {\n display: flex;\n height: calc(100vh - 57px);\n }\n\n .main-wrapper {\n flex: 1;\n display: flex;\n overflow: hidden;\n }\n\n .sidebar {\n width: 200px;\n background: var(--surface-1);\n border-right: 1px solid var(--border);\n padding: 16px;\n overflow-y: auto;\n }\n\n .sidebar-title {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text-muted);\n margin-bottom: 12px;\n }\n\n .template-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 12px;\n background: transparent;\n border: 1px solid #333;\n border-radius: 6px;\n color: #ccc;\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n margin-bottom: 8px;\n transition: all 0.15s;\n }\n\n .template-btn:hover {\n background: var(--surface-2);\n border-color: #444;\n }\n\n .template-btn.active {\n background: rgba(34, 211, 238, 0.1);\n border-color: var(--primary);\n color: var(--primary);\n }\n\n .template-name { font-weight: 500; }\n\n .main {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* Context bar - top */\n .context-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px;\n background: var(--surface-1);\n border-bottom: 1px solid var(--border);\n }\n\n .context-left {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .file-name {\n font-family: ui-monospace, SFMono-Regular, monospace;\n font-size: 13px;\n color: var(--text);\n font-weight: 500;\n }\n\n .file-name:empty::after {\n content: \"Select a template\";\n color: var(--text-muted);\n font-style: italic;\n font-family: inherit;\n }\n\n .page-info {\n font-size: 12px;\n color: var(--text-muted);\n }\n\n .context-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n /* Preview area */\n .preview-area {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #27272a;\n overflow: hidden;\n padding: 24px;\n }\n\n .preview-frame {\n background: #fff;\n border-radius: 4px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\n overflow: hidden;\n transition: opacity 0.2s;\n }\n\n .preview-frame.loading { opacity: 0.4; }\n\n .preview-frame iframe {\n display: block;\n border: none;\n }\n\n .empty-state {\n text-align: center;\n color: var(--text-muted);\n }\n\n .empty-state h2 {\n font-size: 18px;\n margin-bottom: 8px;\n color: var(--text-secondary);\n }\n\n .empty-state p {\n font-size: 14px;\n margin-bottom: 16px;\n }\n\n .empty-state code {\n background: var(--surface-2);\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 13px;\n }\n\n .loading-spinner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--text-muted);\n }\n\n .spinner {\n width: 32px;\n height: 32px;\n border: 2px solid #333;\n border-top-color: var(--primary);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Inspector panel - right side */\n .inspector-panel {\n width: 200px;\n background: var(--surface-1);\n border-left: 1px solid var(--border);\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n }\n\n .inspector-title {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text);\n padding: 12px 16px;\n border-bottom: 1px solid var(--border);\n }\n\n .inspector-content {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n .inspector-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .inspector-section-title {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text-muted);\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .metrics-note {\n font-size: 10px;\n color: var(--text-muted);\n margin-top: 8px;\n font-style: italic;\n }\n\n /* Metrics display */\n .metrics-grid {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .metric-item {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n }\n\n .metric-label {\n font-size: 12px;\n color: var(--text-muted);\n }\n\n .metric-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--primary);\n font-variant-numeric: tabular-nums;\n }\n\n /* Overlay checkboxes */\n .overlay-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .overlay-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .overlay-checkbox:hover {\n color: var(--text);\n }\n\n .overlay-checkbox input {\n appearance: none;\n width: 16px;\n height: 16px;\n border: 1px solid #444;\n border-radius: 3px;\n background: var(--surface-2);\n cursor: pointer;\n position: relative;\n flex-shrink: 0;\n }\n\n .overlay-checkbox input:hover {\n border-color: #555;\n }\n\n .overlay-checkbox input:checked {\n background: var(--primary);\n border-color: var(--primary);\n }\n\n .overlay-checkbox input:checked::after {\n content: \"\";\n position: absolute;\n left: 5px;\n top: 2px;\n width: 4px;\n height: 8px;\n border: solid #000;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .debug-link {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 8px;\n font-size: 12px;\n color: var(--text-muted);\n text-decoration: none;\n transition: color 0.15s;\n }\n\n .debug-link:hover {\n color: var(--primary);\n }\n\n .debug-link svg {\n opacity: 0.7;\n }\n\n /* Console section */\n .console-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n user-select: none;\n }\n\n .console-header:hover {\n color: var(--text-secondary);\n }\n\n .console-toggle {\n transition: transform 0.2s;\n }\n\n .console-toggle.collapsed {\n transform: rotate(-90deg);\n }\n\n .console-content {\n font-size: 12px;\n }\n\n .console-empty {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--text-muted);\n }\n\n .console-empty svg {\n color: #22c55e;\n }\n\n .console-message {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n padding: 4px 0;\n }\n\n .console-message.error {\n color: #ef4444;\n }\n\n .console-message.warning {\n color: #eab308;\n }\n\n .console-message-icon {\n flex-shrink: 0;\n }\n\n .console-message-text {\n word-break: break-all;\n }\n\n /* Buttons */\n .btn {\n padding: 6px 10px;\n background: var(--surface-2);\n border: 1px solid #333;\n border-radius: 5px;\n color: #ccc;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.15s;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n }\n\n .btn:hover { background: #333; border-color: #444; }\n\n .btn-primary {\n background: var(--primary);\n border-color: var(--primary);\n color: #000;\n font-weight: 600;\n }\n\n .btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }\n </style>\n</head>\n<body>\n <header class=\"header\">\n <div class=\"logo\">pdf<span>n</span> <span style=\"font-weight: 400; color: var(--text-muted); font-size: 14px; margin-left: 8px;\">dev</span></div>\n <div class=\"status\">\n <div class=\"status-dot\" id=\"status-dot\"></div>\n <span id=\"status-text\">Connected</span>\n </div>\n </header>\n\n <div class=\"container\">\n <aside class=\"sidebar\">\n <div class=\"sidebar-title\">Templates</div>\n ${\n templates.length > 0\n ? templateList\n : '<div class=\"empty-state\"><p>No templates found</p><code>pdfn add invoice</code></div>'\n }\n </aside>\n\n <div class=\"main-wrapper\">\n <main class=\"main\">\n <!-- Context bar: filename + page info + actions -->\n <div class=\"context-bar\">\n <div class=\"context-left\">\n <div class=\"file-name\" id=\"file-name\"></div>\n <div class=\"page-info\" id=\"page-info\"></div>\n </div>\n <div class=\"context-actions\">\n <a class=\"btn\" id=\"view-pdf\" href=\"#\" target=\"_blank\" title=\"View PDF in browser\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"/>\n </svg>\n View PDF\n </a>\n <button class=\"btn btn-primary\" id=\"download-pdf\" title=\"Download PDF\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"/>\n </svg>\n Download\n </button>\n </div>\n </div>\n\n <!-- Preview area -->\n <div class=\"preview-area\" id=\"preview-area\">\n ${\n activeTemplate\n ? '<div class=\"loading-spinner\"><div class=\"spinner\"></div><span>Loading preview...</span></div>'\n : '<div class=\"empty-state\"><h2>Select a template</h2><p>Choose a template from the sidebar to preview</p></div>'\n }\n </div>\n </main>\n\n <!-- Inspector panel: right side -->\n <aside class=\"inspector-panel\" id=\"inspector-panel\">\n <div class=\"inspector-title\">Inspector</div>\n <div class=\"inspector-content\">\n <div class=\"inspector-section\">\n <div class=\"inspector-section-title\">Performance</div>\n <div class=\"metrics-grid\">\n <div class=\"metric-item\">\n <div class=\"metric-label\">Render</div>\n <div class=\"metric-value\" id=\"metric-render\">--</div>\n </div>\n <div class=\"metric-item\">\n <div class=\"metric-label\">Pagination</div>\n <div class=\"metric-value\" id=\"metric-pagination\">--</div>\n </div>\n <div class=\"metric-item\">\n <div class=\"metric-label\">Pages</div>\n <div class=\"metric-value\" id=\"metric-pages\">--</div>\n </div>\n </div>\n <div class=\"metrics-note\">Measured in browser. Times vary on server.</div>\n </div>\n\n <div class=\"inspector-section\">\n <div class=\"inspector-section-title\">Debug</div>\n <div class=\"overlay-list\">\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-grid\">\n Grid (1cm)\n </label>\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-margins\">\n Margins\n </label>\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-headers\">\n Headers/Footers\n </label>\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-breaks\">\n Page numbers\n </label>\n </div>\n <a class=\"debug-link\" id=\"view-html\" href=\"#\" target=\"_blank\">\n View HTML\n <svg width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"/>\n </svg>\n </a>\n </div>\n\n <div class=\"inspector-section\">\n <div class=\"inspector-section-title console-header\" id=\"console-header\">\n <span>Console</span>\n <svg class=\"console-toggle\" id=\"console-toggle\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"/>\n </svg>\n </div>\n <div class=\"console-content\" id=\"console-content\">\n <div class=\"console-empty\" id=\"console-empty\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"/>\n </svg>\n No issues\n </div>\n <div id=\"console-messages\" style=\"display: none;\"></div>\n </div>\n </div>\n </div>\n </aside>\n </div>\n </div>\n\n <script>\n // Page sizes in points (72 dpi)\n const PAGE_SIZES = {\n A3: { width: 842, height: 1191 },\n A4: { width: 595, height: 842 },\n A5: { width: 420, height: 595 },\n B4: { width: 709, height: 1001 },\n B5: { width: 499, height: 709 },\n Letter: { width: 612, height: 792 },\n Legal: { width: 612, height: 1008 },\n Tabloid: { width: 792, height: 1224 },\n };\n\n const PT_TO_PX = 96 / 72;\n const STORAGE_KEY = 'pdfn-inspector';\n\n let ws;\n let currentTemplate = ${activeTemplate ? `\"${activeTemplate}\"` : \"null\"};\n let templateInfo = {};\n\n // Inspector state with defaults (all overlays off by default)\n let inspectorState = {\n overlays: {\n grid: false,\n margins: false,\n headers: false,\n breaks: false,\n },\n consoleExpanded: true\n };\n\n // Console messages\n let consoleMessages = [];\n\n // Load state from localStorage\n function loadState() {\n try {\n const saved = localStorage.getItem(STORAGE_KEY);\n if (saved) {\n const parsed = JSON.parse(saved);\n inspectorState = { ...inspectorState, ...parsed };\n }\n } catch (e) {}\n }\n\n // Save state to localStorage\n function saveState() {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(inspectorState));\n } catch (e) {}\n }\n\n // Apply state to UI\n function applyState() {\n // Overlay checkboxes\n document.getElementById('overlay-grid').checked = inspectorState.overlays.grid;\n document.getElementById('overlay-margins').checked = inspectorState.overlays.margins;\n document.getElementById('overlay-headers').checked = inspectorState.overlays.headers;\n document.getElementById('overlay-breaks').checked = inspectorState.overlays.breaks;\n\n // Console state\n const consoleContent = document.getElementById('console-content');\n const consoleToggle = document.getElementById('console-toggle');\n if (inspectorState.consoleExpanded) {\n consoleContent.style.display = 'block';\n consoleToggle.classList.remove('collapsed');\n } else {\n consoleContent.style.display = 'none';\n consoleToggle.classList.add('collapsed');\n }\n }\n\n // Toggle console expanded state\n function toggleConsole() {\n inspectorState.consoleExpanded = !inspectorState.consoleExpanded;\n saveState();\n applyState();\n }\n\n // Add console message\n function addConsoleMessage(type, message) {\n consoleMessages.push({ type, message });\n renderConsoleMessages();\n }\n\n // Clear console messages\n function clearConsoleMessages() {\n consoleMessages = [];\n renderConsoleMessages();\n }\n\n // Render console messages\n function renderConsoleMessages() {\n const emptyEl = document.getElementById('console-empty');\n const messagesEl = document.getElementById('console-messages');\n\n if (consoleMessages.length === 0) {\n emptyEl.style.display = 'flex';\n messagesEl.style.display = 'none';\n messagesEl.innerHTML = '';\n } else {\n emptyEl.style.display = 'none';\n messagesEl.style.display = 'block';\n messagesEl.innerHTML = consoleMessages.map(msg =>\n \\`<div class=\"console-message \\${msg.type}\">\n <span class=\"console-message-icon\">\\${msg.type === 'error' ? '✗' : '⚠'}</span>\n <span class=\"console-message-text\">\\${escapeHtml(msg.message)}</span>\n </div>\\`\n ).join('');\n }\n }\n\n // Escape HTML\n function escapeHtml(text) {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n // Get debug query string from overlay state\n function getDebugQuery() {\n const { overlays } = inspectorState;\n const hasAny = Object.values(overlays).some(v => v);\n if (!hasAny) return '';\n\n const params = new URLSearchParams();\n if (overlays.grid) params.set('grid', '1');\n if (overlays.margins) params.set('margins', '1');\n if (overlays.headers) params.set('headers', '1');\n if (overlays.breaks) params.set('breaks', '1');\n\n return '?' + params.toString();\n }\n\n // Check if any overlay is enabled\n function hasAnyOverlay() {\n return Object.values(inspectorState.overlays).some(v => v);\n }\n\n loadState();\n\n function connect() {\n ws = new WebSocket('ws://' + location.host);\n\n ws.onopen = () => {\n document.getElementById('status-dot').classList.remove('disconnected');\n document.getElementById('status-text').textContent = 'Connected';\n };\n\n ws.onclose = () => {\n document.getElementById('status-dot').classList.add('disconnected');\n document.getElementById('status-text').textContent = 'Disconnected';\n setTimeout(connect, 2000);\n };\n\n ws.onmessage = (event) => {\n const data = JSON.parse(event.data);\n if (data.type === 'reload') {\n if (currentTemplate) loadPreview(currentTemplate);\n } else if (data.type === 'templates') {\n updateTemplateList(data.templates);\n }\n };\n }\n\n connect();\n\n // Update template list in sidebar (called when templates are added/removed)\n function updateTemplateList(templates) {\n const sidebar = document.querySelector('.sidebar');\n const titleEl = sidebar.querySelector('.sidebar-title');\n\n // Clear existing buttons\n sidebar.innerHTML = '';\n sidebar.appendChild(titleEl);\n\n if (templates.length === 0) {\n sidebar.innerHTML += '<div class=\"empty-state\"><p>No templates found</p><code>pdfn add invoice</code></div>';\n // Clear preview if no templates\n currentTemplate = null;\n document.getElementById('file-name').textContent = '';\n document.getElementById('page-info').textContent = '';\n document.getElementById('preview-area').innerHTML = '<div class=\"empty-state\"><h2>No templates</h2><p>Add a template to get started</p><code>pdfn add invoice</code></div>';\n return;\n }\n\n // Add template buttons\n templates.forEach(t => {\n const btn = document.createElement('button');\n btn.className = 'template-btn' + (t.id === currentTemplate ? ' active' : '');\n btn.dataset.template = t.id;\n btn.dataset.file = t.file;\n btn.innerHTML = '<span class=\"template-name\">' + t.name + '</span>';\n btn.addEventListener('click', () => loadPreview(t.id));\n sidebar.appendChild(btn);\n });\n\n // If current template was deleted, switch to first template\n const templateIds = templates.map(t => t.id);\n if (currentTemplate && !templateIds.includes(currentTemplate)) {\n loadPreview(templates[0].id);\n }\n }\n\n // Listen for metrics from iframe (postMessage from PDFN script)\n window.addEventListener('message', function(event) {\n if (event.data && event.data.type === 'pdfn:metrics') {\n const metrics = event.data.metrics;\n if (metrics.paginationTime !== undefined) {\n document.getElementById('metric-pagination').textContent = metrics.paginationTime + 'ms';\n }\n if (metrics.pages !== undefined) {\n document.getElementById('metric-pages').textContent = metrics.pages;\n }\n }\n });\n\n function detectPageInfo(html) {\n let pageSize = 'A4';\n let orientation = 'portrait';\n\n // Check for size attribute\n const sizeMatch = html.match(/size=\"([^\"]+)\"/i) || html.match(/data-page-size=\"([^\"]+)\"/i);\n if (sizeMatch) {\n const s = sizeMatch[1];\n if (PAGE_SIZES[s]) pageSize = s;\n }\n\n // Check for orientation attribute\n const orientMatch = html.match(/orientation=\"([^\"]+)\"/i);\n if (orientMatch && orientMatch[1] === 'landscape') {\n orientation = 'landscape';\n }\n\n // Special handling: Tabloid is typically landscape (posters)\n if (html.includes('Tabloid') || html.includes('tabloid')) {\n pageSize = 'Tabloid';\n // Default Tabloid to landscape unless explicitly portrait\n if (!html.includes('orientation=\"portrait\"')) {\n orientation = 'landscape';\n }\n }\n\n return { pageSize, orientation };\n }\n\n function calculateScale(pageSize, orientation) {\n const container = document.getElementById('preview-area');\n const rect = container.getBoundingClientRect();\n const maxWidth = rect.width - 48;\n const maxHeight = rect.height - 48;\n\n const size = PAGE_SIZES[pageSize] || PAGE_SIZES.A4;\n const pageW = (orientation === 'landscape' ? size.height : size.width) * PT_TO_PX;\n const pageH = (orientation === 'landscape' ? size.width : size.height) * PT_TO_PX;\n\n const scale = Math.min(maxWidth / pageW, maxHeight / pageH, 1);\n return { pageW, pageH, scale };\n }\n\n async function loadPreview(templateId) {\n currentTemplate = templateId;\n\n // Get template file name from button\n const activeBtn = document.querySelector('.template-btn[data-template=\"' + templateId + '\"]');\n const fileName = activeBtn ? activeBtn.dataset.file : templateId + '.tsx';\n\n document.querySelectorAll('.template-btn').forEach(btn => {\n btn.classList.toggle('active', btn.dataset.template === templateId);\n });\n\n // Update context bar\n document.getElementById('file-name').textContent = fileName;\n\n const previewArea = document.getElementById('preview-area');\n previewArea.innerHTML = '<div class=\"loading-spinner\"><div class=\"spinner\"></div><span>Rendering...</span></div>';\n\n try {\n const debugQuery = getDebugQuery();\n const htmlRes = await fetch('/api/template/' + templateId + '/html' + debugQuery);\n const html = await htmlRes.text();\n\n templateInfo = detectPageInfo(html);\n document.getElementById('page-info').textContent =\n templateInfo.pageSize + ' · ' + templateInfo.orientation;\n\n // Update metrics (render time from server, pagination from iframe postMessage)\n const renderTime = htmlRes.headers.get('X-Render-Time');\n\n if (renderTime) {\n document.getElementById('metric-render').textContent = renderTime + 'ms';\n }\n\n // Reset pagination metrics (will be updated via postMessage from iframe)\n document.getElementById('metric-pagination').textContent = '--';\n document.getElementById('metric-pages').textContent = '--';\n\n const { pageW, pageH, scale } = calculateScale(templateInfo.pageSize, templateInfo.orientation);\n const displayW = pageW * scale;\n const displayH = pageH * scale;\n\n previewArea.innerHTML = '';\n const frame = document.createElement('div');\n frame.className = 'preview-frame';\n frame.style.width = displayW + 'px';\n frame.style.height = displayH + 'px';\n\n const iframe = document.createElement('iframe');\n iframe.style.width = pageW + 'px';\n iframe.style.height = pageH + 'px';\n iframe.style.transform = 'scale(' + scale + ')';\n iframe.style.transformOrigin = 'top left';\n iframe.srcdoc = html;\n\n frame.classList.add('loading');\n iframe.onload = () => frame.classList.remove('loading');\n\n frame.appendChild(iframe);\n previewArea.appendChild(frame);\n\n // Set up action buttons\n const pdfUrl = '/api/template/' + templateId + '/pdf' + debugQuery;\n const htmlUrl = '/api/template/' + templateId + '/html' + debugQuery;\n\n document.getElementById('view-pdf').href = pdfUrl;\n document.getElementById('view-html').href = htmlUrl;\n\n document.getElementById('download-pdf').onclick = () => {\n const link = document.createElement('a');\n link.href = pdfUrl;\n link.download = templateId + '.pdf';\n link.click();\n };\n\n } catch (err) {\n previewArea.innerHTML = '<div class=\"empty-state\"><h2>Error</h2><p>' + err.message + '</p></div>';\n }\n }\n\n document.querySelectorAll('.template-btn').forEach(btn => {\n btn.addEventListener('click', () => loadPreview(btn.dataset.template));\n });\n\n // Overlay checkbox handlers\n const overlayCheckboxes = ['grid', 'margins', 'headers', 'breaks'];\n overlayCheckboxes.forEach(name => {\n document.getElementById('overlay-' + name).onchange = (e) => {\n inspectorState.overlays[name] = e.target.checked;\n saveState();\n if (currentTemplate) loadPreview(currentTemplate);\n };\n });\n\n // Console header click handler\n document.getElementById('console-header').onclick = toggleConsole;\n\n let resizeTimeout;\n window.addEventListener('resize', () => {\n clearTimeout(resizeTimeout);\n resizeTimeout = setTimeout(() => {\n if (currentTemplate) loadPreview(currentTemplate);\n }, 150);\n });\n\n // Apply saved state and load first template\n applyState();\n ${activeTemplate ? `loadPreview(\"${activeTemplate}\");` : \"\"}\n </script>\n</body>\n</html>`;\n}\n\nasync function startDevServer(options: DevServerOptions) {\n const { port, open, mode } = options;\n const absoluteTemplatesDir = resolve(process.cwd(), TEMPLATES_DIR);\n\n // Show header and initializing message\n console.log(chalk.bold(\"\\n pdfn dev\\n\"));\n console.log(chalk.dim(\" Initializing...\"));\n\n // Scan templates\n let templates = await scanTemplates(absoluteTemplatesDir);\n\n // Show relative path for cleaner output\n const displayPath = TEMPLATES_DIR;\n const templateCount = templates.length === 1 ? \"1 template\" : `${templates.length} templates`;\n\n // Create base server with shared /generate and /health endpoints\n const { app, browserManager } = createBaseServer({\n enableLogging: false, // Dev uses custom logging per route\n onSuccess: (result) => {\n const { metrics } = result;\n console.log(\n chalk.green(\" ✓\"),\n chalk.dim(\"/generate\"),\n chalk.cyan(`${metrics.total}ms`),\n chalk.dim(\"•\"),\n `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`,\n chalk.dim(\"•\"),\n formatBytes(metrics.pdfSize)\n );\n },\n onError: (message) => {\n console.log(chalk.red(\" ✗\"), chalk.dim(\"/generate\"), chalk.red(message));\n },\n });\n const server = createHttpServer(app);\n\n // Create WebSocket server for hot reload\n const wss = new WebSocketServer({ server });\n const clients = new Set<WebSocket>();\n\n wss.on(\"connection\", (ws) => {\n clients.add(ws);\n ws.on(\"close\", () => clients.delete(ws));\n });\n\n wss.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n // Handled by server error handler\n return;\n }\n console.error(chalk.red(\" ✗ WebSocket error:\"), err.message);\n });\n\n function broadcast(message: object) {\n const data = JSON.stringify(message);\n clients.forEach((client) => {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data);\n }\n });\n }\n\n // Create Vite server for template compilation\n // Custom logger to silence Vite's default output (we handle our own logging)\n const viteLogger = {\n info: () => {},\n warn: () => {},\n error: (msg: string) => console.error(chalk.red(\" ✗ Vite:\"), msg),\n warnOnce: () => {},\n hasWarned: false,\n clearScreen: () => {},\n hasErrorLogged: () => false,\n };\n\n const vite = await createViteServer({\n root: process.cwd(),\n mode,\n server: {\n middlewareMode: true,\n hmr: { server } // Use our HTTP server for Vite's WebSocket\n },\n appType: \"custom\",\n customLogger: viteLogger,\n optimizeDeps: {\n include: [\"react\", \"react-dom\"],\n },\n esbuild: {\n jsx: \"automatic\",\n },\n ssr: {\n // Don't externalize these - we need to transform them\n noExternal: [\"@pdfn/react\", \"@pdfn/tailwind\", \"server-only\"],\n },\n plugins: [\n // Pre-compile Tailwind CSS for edge compatibility\n pdfnTailwind({\n templates: [\n join(TEMPLATES_DIR, \"**/*.tsx\"),\n ],\n }),\n {\n name: \"mock-server-only\",\n enforce: \"pre\",\n resolveId(id) {\n if (id === \"server-only\") {\n return { id: \"\\0server-only-mock\", moduleSideEffects: false };\n }\n },\n load(id) {\n if (id === \"\\0server-only-mock\") {\n // Return empty module - we're in SSR context so server-only is fine\n return \"export default {};\";\n }\n },\n },\n ],\n });\n\n\n // Watch for template and CSS changes\n // Watch templates dir and styles.css + styles/ directory for CSS HMR\n const watchPaths = [\n absoluteTemplatesDir,\n join(absoluteTemplatesDir, \"styles.css\"),\n join(absoluteTemplatesDir, \"styles\"),\n ];\n const watcher = chokidar.watch(watchPaths, {\n ignored: /(^|[\\/\\\\])\\../,\n persistent: true,\n });\n\n // Helper to check if a file is a template (matches what we show in sidebar)\n function isTemplateFile(filePath: string): boolean {\n const fileName = filePath.split(\"/\").pop() || \"\";\n // Must be a .tsx file in the root of templates dir (not in subdirectories)\n if (!fileName.endsWith(\".tsx\")) return false;\n // Check if it's a direct child of templates dir\n const relativePath = filePath.replace(absoluteTemplatesDir + \"/\", \"\");\n if (relativePath.includes(\"/\")) return false;\n return true;\n }\n\n // Helper to check if file is a code file (tsx/ts/js/jsx)\n function isCodeFile(filePath: string): boolean {\n return /\\.(tsx?|jsx?)$/.test(filePath);\n }\n\n // Helper to check if file is a CSS file in templates\n function isCssFile(filePath: string): boolean {\n return filePath.endsWith(\".css\");\n }\n\n // Suppress logging during initial scan\n let watcherReady = false;\n\n watcher.on(\"ready\", () => {\n watcherReady = true;\n });\n\n watcher.on(\"change\", async (filePath) => {\n if (!watcherReady) return;\n const fileName = filePath.split(\"/\").pop() || filePath;\n\n // Handle CSS file changes (styles.css or styles/*.css)\n if (isCssFile(filePath)) {\n console.log(chalk.blue(\" ↻\"), fileName, chalk.dim(\"changed\"));\n\n // Invalidate the virtual Tailwind CSS module to force recompilation\n const virtualMod = vite.moduleGraph.getModuleById(\"\\0virtual:pdfn-tailwind-css\");\n if (virtualMod) {\n vite.moduleGraph.invalidateModule(virtualMod);\n // Invalidate all modules that import the virtual module\n for (const importer of virtualMod.importers) {\n vite.moduleGraph.invalidateModule(importer);\n }\n }\n\n templates = await scanTemplates(absoluteTemplatesDir);\n broadcast({ type: \"reload\" });\n return;\n }\n\n // Log all code file changes (templates and components)\n if (isCodeFile(filePath)) {\n console.log(chalk.blue(\" ↻\"), fileName, chalk.dim(\"changed\"));\n\n // Invalidate the changed module and its dependencies in Vite's SSR cache\n const mod = vite.moduleGraph.getModuleById(filePath);\n if (mod) {\n vite.moduleGraph.invalidateModule(mod);\n }\n\n // Also invalidate the virtual Tailwind CSS module to force recompilation\n const virtualMod = vite.moduleGraph.getModuleById(\"\\0virtual:pdfn-tailwind-css\");\n if (virtualMod) {\n vite.moduleGraph.invalidateModule(virtualMod);\n // Invalidate all modules that import the virtual module\n for (const importer of virtualMod.importers) {\n vite.moduleGraph.invalidateModule(importer);\n }\n }\n }\n templates = await scanTemplates(absoluteTemplatesDir);\n broadcast({ type: \"reload\" });\n });\n\n watcher.on(\"add\", async (filePath) => {\n if (!watcherReady) return;\n const oldCount = templates.length;\n templates = await scanTemplates(absoluteTemplatesDir);\n // Only log if a new template was actually added (not components)\n if (templates.length > oldCount && isTemplateFile(filePath)) {\n const fileName = filePath.split(\"/\").pop() || filePath;\n console.log(chalk.green(\" +\"), fileName, chalk.dim(\"added\"));\n }\n // Send updated template list so sidebar can be refreshed\n broadcast({ type: \"templates\", templates: templates.map(t => ({ id: t.id, name: t.name, file: t.file })) });\n });\n\n watcher.on(\"unlink\", async (filePath) => {\n if (!watcherReady) return;\n const oldCount = templates.length;\n const fileName = filePath.split(\"/\").pop() || filePath;\n templates = await scanTemplates(absoluteTemplatesDir);\n // Only log if a template was actually removed (not components)\n if (templates.length < oldCount && isTemplateFile(filePath)) {\n console.log(chalk.red(\" -\"), fileName, chalk.dim(\"removed\"));\n }\n // Send updated template list so sidebar can be refreshed\n broadcast({ type: \"templates\", templates: templates.map(t => ({ id: t.id, name: t.name, file: t.file })) });\n });\n\n // Serve preview UI\n app.get(\"/\", (_req: Request, res: Response) => {\n const activeTemplate = templates[0]?.id ?? null;\n res.send(createPreviewHTML(templates, activeTemplate));\n });\n\n // API: Get template code\n app.get(\"/api/template/:id/code\", (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).send(\"Template not found\");\n return;\n }\n\n try {\n const code = readFileSync(template.path, \"utf-8\");\n res.type(\"text/plain\").send(code);\n } catch {\n res.status(500).send(\"Error reading template\");\n }\n });\n\n // Helper: Render a template to HTML using Vite\n // Templates use default parameter values for sample data (React Email pattern)\n async function renderTemplate(\n template: TemplateInfo,\n debugOptions: DebugOptions | false = false\n ): Promise<string> {\n const mod = await vite.ssrLoadModule(template.path);\n const Component = mod.default;\n const { render } = await vite.ssrLoadModule(\"@pdfn/react\");\n // Call with empty props - component's default parameter values provide sample data\n // Debug options are passed directly to render()\n return render(Component({}), { debug: debugOptions || undefined });\n }\n\n // Parse debug options from query params\n function parseDebugOptions(query: Record<string, unknown>): DebugOptions | false {\n const options: DebugOptions = {\n grid: query.grid === \"1\",\n margins: query.margins === \"1\",\n headers: query.headers === \"1\",\n breaks: query.breaks === \"1\",\n };\n\n // Return false if no options enabled\n const hasAny = Object.values(options).some((v) => v);\n return hasAny ? options : false;\n }\n\n // API: Get rendered HTML\n app.get(\"/api/template/:id/html\", async (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).send(\"Template not found\");\n return;\n }\n\n try {\n const start = performance.now();\n const debugOptions = parseDebugOptions(req.query as Record<string, unknown>);\n const html = await renderTemplate(template, debugOptions);\n const duration = Math.round(performance.now() - start);\n\n // Count pages from rendered HTML (look for pagedjs page markers)\n const pageMatches = html.match(/class=\"pagedjs_page\"/g);\n const pageCount = pageMatches ? pageMatches.length : 1;\n\n // Log render\n console.log(\n chalk.green(\" ✓\"),\n template.file,\n chalk.dim(\"→ HTML\"),\n chalk.cyan(`${duration}ms`)\n );\n\n res.setHeader(\"X-Render-Time\", duration.toString());\n res.setHeader(\"X-Page-Count\", pageCount.toString());\n // Note: Pagination time is measured client-side after Paged.js runs\n res.type(\"text/html\").send(html);\n } catch (error) {\n console.log(chalk.red(\" ✗\"), template.file, chalk.red(\"render failed\"));\n console.error(chalk.dim(\" \"), error);\n res.status(500).send(`Error rendering template: ${error}`);\n }\n });\n\n // Helper: Format bytes for display\n function formatBytes(bytes: number): string {\n if (bytes < 1024) return bytes + \"B\";\n if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + \"KB\";\n return (bytes / (1024 * 1024)).toFixed(2) + \"MB\";\n }\n\n // API: Generate PDF\n app.get(\"/api/template/:id/pdf\", async (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).send(\"Template not found\");\n return;\n }\n\n try {\n const debugOptions = parseDebugOptions(req.query as Record<string, unknown>);\n const html = await renderTemplate(template, debugOptions);\n const result = await browserManager.withPage(async (page) => {\n return generatePdf(page, html, { timeout: 30000 });\n });\n\n // Log PDF generation - first line: request summary\n const { metrics, warnings, assets } = result;\n console.log(\n chalk.green(\" ✓\"),\n template.file,\n chalk.dim(\"→ PDF •\"),\n chalk.cyan(`${metrics.total}ms`),\n chalk.dim(\"•\"),\n formatBytes(metrics.pdfSize)\n );\n\n // Second line: details (pages, assets, timing) - all separated by •\n const pageStr = `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`;\n const images = assets.filter((a) => a.type === \"image\");\n const fonts = assets.filter((a) => a.type === \"font\");\n const assetParts: string[] = [];\n if (images.length > 0) assetParts.push(`${images.length} image${images.length > 1 ? \"s\" : \"\"}`);\n if (fonts.length > 0) assetParts.push(`${fonts.length} font${fonts.length > 1 ? \"s\" : \"\"}`);\n const assetStr = assetParts.length > 0 ? assetParts.join(\" • \") + \" • \" : \"\";\n const timingStr = `load ${metrics.contentLoad}ms • paginate ${metrics.pagedJs}ms • capture ${metrics.pdfCapture}ms`;\n console.log(chalk.dim(` ${pageStr} • ${assetStr}${timingStr}`));\n\n // Log warnings\n if (warnings.length > 0) {\n warnings.forEach((w) => {\n console.log(chalk.yellow(\" ⚠\"), chalk.yellow(w));\n });\n }\n\n // Add metrics headers\n res.setHeader(\"X-PDF-Total-Time\", metrics.total.toString());\n res.setHeader(\"X-PDF-Pages\", metrics.pageCount.toString());\n res.setHeader(\"X-PDF-Size\", metrics.pdfSize.toString());\n res.setHeader(\"X-PDF-Capture-Time\", metrics.pdfCapture.toString());\n res.setHeader(\"X-PDF-Assets\", result.assets.length.toString());\n res.setHeader(\"X-PDF-Warnings\", warnings.length.toString());\n\n res.setHeader(\"Content-Type\", \"application/pdf\");\n res.setHeader(\"Content-Disposition\", `inline; filename=\"${template.id}.pdf\"`);\n res.send(result.buffer);\n } catch (error) {\n console.log(chalk.red(\" ✗\"), template.file, chalk.red(\"PDF generation failed\"));\n console.error(chalk.dim(\" \"), error);\n res.status(500).send(`Error generating PDF: ${error}`);\n }\n });\n\n // API: Generate PDF and return metrics (JSON)\n app.get(\"/api/template/:id/pdf-metrics\", async (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).json({ error: \"Template not found\" });\n return;\n }\n\n try {\n const debugOptions = parseDebugOptions(req.query as Record<string, unknown>);\n const html = await renderTemplate(template, debugOptions);\n const result = await browserManager.withPage(async (page) => {\n return generatePdf(page, html, { timeout: 30000 });\n });\n\n // Log PDF metrics - first line: request summary\n const { metrics, warnings, assets } = result;\n console.log(\n chalk.green(\" ✓\"),\n template.file,\n chalk.dim(\"→ PDF metrics •\"),\n chalk.cyan(`${metrics.total}ms`),\n chalk.dim(\"•\"),\n formatBytes(metrics.pdfSize)\n );\n\n // Second line: details (pages, assets, timing) - all separated by •\n {\n const pageStr = `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`;\n const images = assets.filter((a) => a.type === \"image\");\n const fonts = assets.filter((a) => a.type === \"font\");\n const assetParts: string[] = [];\n if (images.length > 0) assetParts.push(`${images.length} image${images.length > 1 ? \"s\" : \"\"}`);\n if (fonts.length > 0) assetParts.push(`${fonts.length} font${fonts.length > 1 ? \"s\" : \"\"}`);\n const assetStr = assetParts.length > 0 ? assetParts.join(\" • \") + \" • \" : \"\";\n const timingStr = `load ${metrics.contentLoad}ms • paginate ${metrics.pagedJs}ms • capture ${metrics.pdfCapture}ms`;\n console.log(chalk.dim(` ${pageStr} • ${assetStr}${timingStr}`));\n }\n\n if (warnings.length > 0) {\n warnings.forEach((w) => {\n console.log(chalk.yellow(\" ⚠\"), chalk.yellow(w));\n });\n }\n\n res.json({\n metrics: result.metrics,\n assets: result.assets,\n warnings: result.warnings,\n });\n } catch (error) {\n console.log(chalk.red(\" ✗\"), template.file, chalk.red(\"PDF metrics failed\"));\n console.error(chalk.dim(\" \"), error);\n res.status(500).json({ error: `Error generating PDF: ${error}` });\n }\n });\n\n // Start server\n await new Promise<void>((resolve, reject) => {\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n console.error(chalk.red(`\\n ✗ Port ${port} is already in use.\\n`));\n console.error(chalk.dim(` Either stop the existing server or use a different port:`));\n console.error(chalk.dim(` npx pdfn dev --port ${port + 1}\\n`));\n process.exit(1);\n }\n reject(err);\n });\n server.listen(port, () => resolve());\n });\n\n // Pre-launch Chromium for PDF generation\n await browserManager.getBrowser();\n\n // Graceful shutdown\n const shutdown = async () => {\n console.log(chalk.dim(\"\\n Shutting down...\"));\n watcher.close();\n await vite.close();\n await browserManager.close();\n server.close();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n\n // Open Chromium (same browser used for PDF generation = true WYSIWYG)\n function openChromium() {\n const chromiumPath = puppeteer.executablePath();\n console.log(chalk.dim(\" Opening in Chromium...\\n\"));\n spawn(chromiumPath, [`http://localhost:${port}`], {\n detached: true,\n stdio: \"ignore\",\n }).unref();\n }\n\n console.log(chalk.dim(` Templates: ${displayPath} (${templateCount})`));\n console.log(chalk.green(`\\n ✓ Ready at ${chalk.cyan(`http://localhost:${port}`)}\\n`));\n\n if (!open) {\n console.log(chalk.dim(` Tip: PDFs are generated with Chromium. For accurate preview,`));\n console.log(chalk.dim(` open in Chrome or Chromium-based browsers.\\n`));\n }\n\n console.log(chalk.dim(` Shortcuts`));\n console.log(chalk.dim(` › ${chalk.white(\"o\")} open in Chromium`));\n console.log(chalk.dim(` › ${chalk.white(\"q\")} quit\\n`));\n\n if (open) {\n openChromium();\n }\n\n // Keyboard shortcuts\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (key: string) => {\n if (key === \"o\" || key === \"O\") {\n openChromium();\n } else if (key === \"q\" || key === \"Q\" || key === \"\\u0003\") {\n // q or Ctrl+C\n shutdown();\n }\n });\n }\n}\n\nexport const devCommand = new Command(\"dev\")\n .description(\"Start development server with live preview\")\n .option(\"--port <number>\", \"Server port (env: PDFN_PORT)\", process.env.PDFN_PORT ?? \"3456\")\n .option(\"--open\", \"Open browser automatically\")\n .option(\"--mode <mode>\", \"Environment mode (loads .env.[mode])\", \"development\")\n .action(async (options) => {\n // Load environment variables based on mode (Vite pattern)\n loadEnv(options.mode);\n\n const port = parseInt(options.port, 10);\n\n await startDevServer({\n port,\n open: options.open ?? false,\n mode: options.mode,\n });\n });\n","import express from \"express\";\nimport type { Express, Request, Response, NextFunction } from \"express\";\nimport { BrowserManager } from \"./browser\";\nimport { createGenerateHandler } from \"./routes\";\nimport { type PdfResult } from \"./pdf\";\n\nexport interface BaseServerOptions {\n /** Max concurrent pages (default: env.PDFN_MAX_CONCURRENT || 5) */\n maxConcurrent?: number;\n /** Request timeout in ms (default: env.PDFN_TIMEOUT || 30000) */\n timeout?: number;\n /** Enable request logging (default: true) */\n enableLogging?: boolean;\n /** Custom logger for requests */\n onRequest?: (method: string, path: string, status: number, duration: number, extra?: string) => void;\n /** Custom logger for PDF details */\n onPdfResult?: (result: PdfResult) => void;\n /** Callback on successful PDF generation */\n onSuccess?: (result: PdfResult) => void;\n /** Custom logger for errors */\n onError?: (message: string) => void;\n}\n\nexport interface BaseServer {\n app: Express;\n browserManager: BrowserManager;\n maxConcurrent: number;\n timeout: number;\n}\n\n/**\n * Create a base PDFN server with common middleware and routes.\n *\n * This is shared between `dev` and `serve` commands.\n * Returns the Express app and BrowserManager for further customization.\n *\n * Includes:\n * - JSON body parsing (50mb limit)\n * - Request logging middleware (optional)\n * - POST /generate endpoint\n * - GET /health endpoint\n */\nexport function createBaseServer(options: BaseServerOptions = {}): BaseServer {\n const maxConcurrent =\n options.maxConcurrent ??\n parseInt(process.env.PDFN_MAX_CONCURRENT ?? \"5\", 10);\n const timeout =\n options.timeout ?? parseInt(process.env.PDFN_TIMEOUT ?? \"30000\", 10);\n const enableLogging = options.enableLogging ?? true;\n\n const app = express();\n const browserManager = new BrowserManager({ maxConcurrent, timeout });\n\n // JSON body parsing\n app.use(express.json({ limit: \"50mb\" }));\n\n // Request logging middleware\n if (enableLogging && options.onRequest) {\n const onRequest = options.onRequest;\n const onPdfResult = options.onPdfResult;\n\n app.use((req: Request, res: Response, next: NextFunction) => {\n // Skip noisy requests\n const skipPaths = [\"/favicon.ico\", \"/robots.txt\"];\n if (skipPaths.includes(req.path)) {\n next();\n return;\n }\n\n const start = performance.now();\n\n res.on(\"finish\", () => {\n const duration = performance.now() - start;\n\n // For /generate, include page count and size\n let extra: string | undefined;\n if (req.path === \"/generate\" && res.statusCode === 200) {\n const pages = res.getHeader(\"X-PDFN-Page-Count\");\n const size = Number(res.getHeader(\"X-PDFN-PDF-Size\")) || 0;\n const sizeKB = (size / 1024).toFixed(1);\n extra = `${pages} pages • ${sizeKB}KB`;\n }\n\n onRequest(req.method, req.path, res.statusCode, duration, extra);\n\n // Log PDF details if available\n const pdfResult = (res as any)._pdfResult as PdfResult | undefined;\n if (pdfResult && onPdfResult) {\n onPdfResult(pdfResult);\n }\n });\n\n next();\n });\n }\n\n // Health check endpoint\n app.get(\"/health\", (_req: Request, res: Response) => {\n res.json({\n status: \"ok\",\n browser: browserManager.isConnected() ? \"connected\" : \"disconnected\",\n activePages: browserManager.getActivePages(),\n maxConcurrent: browserManager.getMaxConcurrent(),\n });\n });\n\n // PDF generation endpoint\n app.post(\n \"/generate\",\n createGenerateHandler(browserManager, {\n timeout,\n onSuccess: options.onSuccess,\n onError: options.onError,\n })\n );\n\n return {\n app,\n browserManager,\n maxConcurrent,\n timeout,\n };\n}\n","import puppeteer, { Browser, Page } from \"puppeteer\";\n\nexport interface BrowserManagerOptions {\n /** Max concurrent pages (default: env.PDFN_MAX_CONCURRENT || 5) */\n maxConcurrent?: number;\n /** Request timeout in ms (default: env.PDFN_TIMEOUT || 30000) */\n timeout?: number;\n}\n\n/**\n * Manages a single Puppeteer browser instance with multiple concurrent pages\n *\n * Architecture: Single browser + multiple pages (industry standard pattern)\n * - Lower memory footprint (~150MB browser + ~30MB/page)\n * - Fast page creation (~50ms vs ~1-2s for new browser)\n * - Auto-restart on browser crash/disconnect\n */\nexport class BrowserManager {\n private browser: Browser | null = null;\n private launching: Promise<Browser> | null = null;\n private activePages = 0;\n private maxConcurrent: number;\n private timeout: number;\n\n constructor(options: BrowserManagerOptions = {}) {\n this.maxConcurrent =\n options.maxConcurrent ??\n parseInt(process.env.PDFN_MAX_CONCURRENT ?? \"5\", 10);\n this.timeout =\n options.timeout ?? parseInt(process.env.PDFN_TIMEOUT ?? \"30000\", 10);\n }\n\n /**\n * Get or create the browser instance\n */\n async getBrowser(): Promise<Browser> {\n if (this.browser?.connected) {\n return this.browser;\n }\n\n // If already launching, wait for that\n if (this.launching) {\n return this.launching;\n }\n\n // Launch new browser\n this.launching = puppeteer.launch({\n headless: true,\n args: [\n \"--no-sandbox\",\n \"--disable-setuid-sandbox\",\n \"--disable-dev-shm-usage\",\n \"--disable-gpu\",\n \"--disable-extensions\",\n \"--mute-audio\",\n \"--disable-notifications\",\n ],\n });\n\n try {\n this.browser = await this.launching;\n this.setupBrowserListeners(this.browser);\n return this.browser;\n } finally {\n this.launching = null;\n }\n }\n\n /**\n * Setup browser event listeners for auto-restart on crash\n */\n private setupBrowserListeners(browser: Browser): void {\n browser.on(\"disconnected\", () => {\n this.browser = null;\n // activePages will naturally drain as withPage catches errors\n });\n }\n\n /**\n * Create a new page for PDF generation\n */\n async createPage(): Promise<Page> {\n const browser = await this.getBrowser();\n const page = await browser.newPage();\n page.setDefaultTimeout(this.timeout);\n return page;\n }\n\n /**\n * Execute a function with a managed page\n *\n * This pattern ensures:\n * - Concurrency limits are respected\n * - Pages are always closed after use\n * - Active page count is accurate\n *\n * @throws Error if max concurrent pages reached\n */\n async withPage<T>(fn: (page: Page) => Promise<T>): Promise<T> {\n if (this.activePages >= this.maxConcurrent) {\n throw new Error(\"Server busy - max concurrent requests reached\");\n }\n\n this.activePages++;\n let page: Page | null = null;\n\n try {\n page = await this.createPage();\n return await fn(page);\n } finally {\n this.activePages--;\n if (page) {\n await page.close().catch(() => {\n // Ignore close errors (browser may have disconnected)\n });\n }\n }\n }\n\n /**\n * Check if browser is connected\n */\n isConnected(): boolean {\n return this.browser?.connected ?? false;\n }\n\n /**\n * Get current number of active pages\n */\n getActivePages(): number {\n return this.activePages;\n }\n\n /**\n * Get max concurrent pages limit\n */\n getMaxConcurrent(): number {\n return this.maxConcurrent;\n }\n\n /**\n * Get configured timeout\n */\n getTimeout(): number {\n return this.timeout;\n }\n\n /**\n * Close the browser and clean up\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close();\n this.browser = null;\n }\n }\n}\n","/**\n * Simple debug logging utility\n *\n * Enable with DEBUG=pdfn:cli or DEBUG=pdfn:* or DEBUG=pdfn\n *\n * This is a lightweight alternative to the `debug` npm package.\n * Supports namespace filtering similar to the debug package convention.\n */\n\n// Debug logging - enable with DEBUG=pdfn:cli or DEBUG=pdfn:* or DEBUG=pdfn\nconst debugEnv = process.env.DEBUG ?? \"\";\nconst isEnabled =\n debugEnv.includes(\"pdfn:cli\") ||\n debugEnv.includes(\"pdfn:*\") ||\n debugEnv === \"pdfn\" ||\n debugEnv.includes(\"pdfn,\") ||\n debugEnv.endsWith(\",pdfn\");\n\n/**\n * Debug logger - only logs when DEBUG=pdfn:cli (or pdfn:* or pdfn) is set\n */\nexport const debug = isEnabled\n ? (message: string, ...args: unknown[]) => {\n console.log(`[pdfn:cli] ${message}`, ...args);\n }\n : () => {};\n\n/**\n * Check if debug logging is enabled\n */\nexport const isDebugEnabled = () => isEnabled;\n","import type { Page, PDFOptions, HTTPRequest, HTTPResponse } from \"puppeteer\";\nimport { debug } from \"../utils/debug\";\n\nexport interface PdfGenerationOptions {\n /** PDF format (default: A4) */\n format?: \"A4\" | \"Letter\" | \"Legal\" | \"Tabloid\" | \"A3\" | \"A5\";\n /** Print background graphics */\n printBackground?: boolean;\n /** Timeout for waiting for ready state (ms) */\n timeout?: number;\n}\n\n/** Asset information tracked during PDF generation */\nexport interface AssetInfo {\n /** Asset URL */\n url: string;\n /** Asset type (image, font, stylesheet, script, other) */\n type: \"image\" | \"font\" | \"stylesheet\" | \"script\" | \"other\";\n /** Size in bytes (0 if failed) */\n size: number;\n /** Load time in ms */\n duration: number;\n /** Whether the asset loaded successfully */\n success: boolean;\n /** Error message if failed */\n error?: string;\n}\n\nexport interface PdfResult {\n /** PDF buffer */\n buffer: Buffer;\n /** Generation metrics */\n metrics: {\n /** Total generation time in ms */\n total: number;\n /** Time waiting for content to load */\n contentLoad: number;\n /** Time waiting for Paged.js */\n pagedJs: number;\n /** Time for PDF capture */\n pdfCapture: number;\n /** Number of pages */\n pageCount: number;\n /** PDF file size in bytes */\n pdfSize: number;\n };\n /** Assets loaded during generation */\n assets: AssetInfo[];\n /** Warnings detected during generation */\n warnings: string[];\n}\n\n/** Size threshold for large asset warning (200KB - web best practice) */\nconst LARGE_ASSET_THRESHOLD = 200 * 1024;\n\n/** Duration threshold for slow asset warning (1000ms - lenient for fonts) */\nconst SLOW_ASSET_THRESHOLD = 1000;\n\n/** Determine asset type from resource type */\nfunction getAssetType(resourceType: string): AssetInfo[\"type\"] {\n switch (resourceType) {\n case \"image\":\n return \"image\";\n case \"font\":\n return \"font\";\n case \"stylesheet\":\n return \"stylesheet\";\n case \"script\":\n return \"script\";\n default:\n return \"other\";\n }\n}\n\n/** Get short URL for display (remove data: prefix, truncate long URLs) */\nfunction getShortUrl(url: string): string {\n if (url.startsWith(\"data:\")) {\n const match = url.match(/^data:([^;,]+)/);\n return match ? `data:${match[1]}...` : \"data:...\";\n }\n if (url.length > 80) {\n return url.substring(0, 77) + \"...\";\n }\n return url;\n}\n\n/**\n * Generate PDF from HTML content using a Puppeteer page\n */\nexport async function generatePdf(\n page: Page,\n html: string,\n options: PdfGenerationOptions = {}\n): Promise<PdfResult> {\n const {\n format = \"A4\",\n printBackground = true,\n timeout = 30000,\n } = options;\n\n const startTime = performance.now();\n let contentLoadTime = 0;\n let pagedJsTime = 0;\n let pdfCaptureTime = 0;\n let pageCount = 0;\n\n // Asset tracking\n const assets: AssetInfo[] = [];\n const requestStartTimes = new Map<string, number>();\n const warnings: string[] = [];\n\n // Request handler to track start times\n const onRequest = (request: HTTPRequest) => {\n const url = request.url();\n const resourceType = request.resourceType();\n\n // Only track relevant resource types\n if ([\"image\", \"font\", \"stylesheet\", \"script\"].includes(resourceType)) {\n requestStartTimes.set(url, performance.now());\n }\n };\n\n // Response handler to track completed requests\n const onResponse = (response: HTTPResponse) => {\n const url = response.url();\n const request = response.request();\n const resourceType = request.resourceType();\n const startTime = requestStartTimes.get(url);\n\n if (startTime === undefined) return;\n\n const duration = Math.round(performance.now() - startTime);\n const status = response.status();\n const success = status >= 200 && status < 400;\n\n // Get content length from headers\n const contentLength = response.headers()[\"content-length\"];\n const size = contentLength ? parseInt(contentLength, 10) : 0;\n\n const asset: AssetInfo = {\n url: getShortUrl(url),\n type: getAssetType(resourceType),\n size,\n duration,\n success,\n };\n\n if (!success) {\n asset.error = `HTTP ${status}`;\n warnings.push(`Failed: ${asset.url} (${status})`);\n } else {\n if (size > LARGE_ASSET_THRESHOLD) {\n warnings.push(`Large: ${asset.url} (${(size / 1024).toFixed(0)}KB)`);\n }\n if (duration > SLOW_ASSET_THRESHOLD) {\n warnings.push(`Slow: ${asset.url} (${duration}ms)`);\n }\n }\n\n assets.push(asset);\n requestStartTimes.delete(url);\n };\n\n // Request failed handler\n const onRequestFailed = (request: HTTPRequest) => {\n const url = request.url();\n const resourceType = request.resourceType();\n const startTime = requestStartTimes.get(url);\n\n if (startTime === undefined) return;\n\n const duration = Math.round(performance.now() - startTime);\n const failure = request.failure();\n const errorText = failure?.errorText || \"Unknown error\";\n\n const asset: AssetInfo = {\n url: getShortUrl(url),\n type: getAssetType(resourceType),\n size: 0,\n duration,\n success: false,\n error: errorText,\n };\n\n warnings.push(`Failed: ${asset.url} (${errorText})`);\n assets.push(asset);\n requestStartTimes.delete(url);\n };\n\n // Set up request interception\n page.on(\"request\", onRequest);\n page.on(\"response\", onResponse);\n page.on(\"requestfailed\", onRequestFailed);\n\n try {\n // Set content and wait for network idle\n const contentStart = performance.now();\n await page.setContent(html, {\n waitUntil: \"networkidle0\",\n timeout,\n });\n contentLoadTime = performance.now() - contentStart;\n\n // Wait for PDFN.ready to be true (Paged.js completion)\n const pagedStart = performance.now();\n await page.waitForFunction(\n () => (window as any).PDFN?.ready === true,\n { timeout }\n );\n pagedJsTime = performance.now() - pagedStart;\n\n // Get page count from PDFN metrics\n pageCount = await page.evaluate(() => {\n return (window as any).PDFN?.metrics?.pages ?? 1;\n });\n\n // Generate PDF\n const pdfStart = performance.now();\n const pdfOptions: PDFOptions = {\n format,\n printBackground,\n preferCSSPageSize: true,\n tagged: true, // Accessibility: generates tagged PDF for screen readers\n outline: true, // Accessibility: auto-generates bookmarks from headings\n };\n\n const buffer = await page.pdf(pdfOptions);\n pdfCaptureTime = performance.now() - pdfStart;\n\n const totalTime = performance.now() - startTime;\n const pdfBuffer = Buffer.from(buffer);\n\n debug(\n `pdf: ${Math.round(totalTime)}ms (load: ${Math.round(contentLoadTime)}ms, paged: ${Math.round(pagedJsTime)}ms, capture: ${Math.round(pdfCaptureTime)}ms) - ${pageCount} pages, ${(pdfBuffer.length / 1024).toFixed(1)}KB`\n );\n\n if (assets.length > 0) {\n debug(`assets: ${assets.length} (${assets.filter(a => !a.success).length} failed)`);\n }\n\n if (warnings.length > 0) {\n warnings.forEach(w => debug(`warning: ${w}`));\n }\n\n return {\n buffer: pdfBuffer,\n metrics: {\n total: Math.round(totalTime),\n contentLoad: Math.round(contentLoadTime),\n pagedJs: Math.round(pagedJsTime),\n pdfCapture: Math.round(pdfCaptureTime),\n pageCount,\n pdfSize: pdfBuffer.length,\n },\n assets,\n warnings,\n };\n } finally {\n // Clean up event listeners\n page.off(\"request\", onRequest);\n page.off(\"response\", onResponse);\n page.off(\"requestfailed\", onRequestFailed);\n\n // Close the page after use\n await page.close().catch(() => {});\n }\n}\n","import type { Request, Response } from \"express\";\nimport type { BrowserManager } from \"./browser\";\nimport { generatePdf, type PdfResult } from \"./pdf\";\n\ninterface GenerateRequestBody {\n html?: string;\n options?: {\n timeout?: number;\n printBackground?: boolean;\n preferCSSPageSize?: boolean;\n };\n}\n\ninterface GenerateHandlerOptions {\n /** Default timeout in ms (default: 30000) */\n timeout?: number;\n /** Optional logger for PDF generation results */\n onSuccess?: (result: PdfResult) => void;\n /** Optional logger for errors */\n onError?: (error: string) => void;\n}\n\n/**\n * Create a /generate POST handler for PDF generation\n *\n * This is shared between `dev` and `serve` commands to avoid duplication.\n * Each server provides its own BrowserManager instance.\n *\n * @example\n * ```ts\n * const browserManager = new BrowserManager({ maxConcurrent: 5 });\n * app.post(\"/generate\", createGenerateHandler(browserManager));\n * ```\n */\nexport function createGenerateHandler(\n browserManager: BrowserManager,\n options: GenerateHandlerOptions = {}\n) {\n const { timeout = 30000, onSuccess, onError } = options;\n\n return async (req: Request, res: Response) => {\n const { html, options: pdfOptions } = req.body as GenerateRequestBody;\n const format = req.query.format as string | undefined;\n\n if (!html) {\n res.status(400).json({ error: \"HTML content is required\" });\n return;\n }\n\n // Return HTML directly if format=html (for debugging)\n if (format === \"html\") {\n res.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n res.send(html);\n return;\n }\n\n try {\n const result = await browserManager.withPage(async (page) => {\n return generatePdf(page, html, {\n ...pdfOptions,\n timeout: pdfOptions?.timeout ?? timeout,\n });\n });\n\n // Set response headers with metrics\n res.setHeader(\"Content-Type\", \"application/pdf\");\n res.setHeader(\"X-PDFN-Total-Time\", result.metrics.total.toString());\n res.setHeader(\"X-PDFN-Content-Load\", result.metrics.contentLoad.toString());\n res.setHeader(\"X-PDFN-PagedJs-Time\", result.metrics.pagedJs.toString());\n res.setHeader(\"X-PDFN-PDF-Capture\", result.metrics.pdfCapture.toString());\n res.setHeader(\"X-PDFN-Page-Count\", result.metrics.pageCount.toString());\n res.setHeader(\"X-PDFN-PDF-Size\", result.metrics.pdfSize.toString());\n\n // Attach result for logging middleware (used by serve command)\n (res as any)._pdfResult = result;\n\n // Call success callback if provided\n onSuccess?.(result);\n\n res.send(result.buffer);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n\n // Call error callback if provided\n onError?.(message);\n\n if (message.includes(\"Server busy\")) {\n res.status(503).json({ error: message });\n return;\n }\n\n res.status(500).json({ error: message });\n }\n };\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { config } from \"dotenv\";\n\n/**\n * Load environment variables following Vite's pattern.\n * Priority (later overrides earlier):\n * .env → .env.local → .env.[mode] → .env.[mode].local\n *\n * @param mode - Environment mode (e.g., \"development\", \"production\")\n */\nexport function loadEnv(mode: string): void {\n const cwd = process.cwd();\n\n // Files in order of priority (first loaded = lowest priority)\n const envFiles = [\n \".env\",\n \".env.local\",\n `.env.${mode}`,\n `.env.${mode}.local`,\n ];\n\n for (const file of envFiles) {\n const filePath = resolve(cwd, file);\n if (existsSync(filePath)) {\n // quiet: true suppresses dotenv's verbose output in v17+\n config({ path: filePath, override: true, quiet: true });\n }\n }\n}\n","import { Command } from \"commander\";\nimport { createServer } from \"../server/index\";\nimport { logger } from \"../utils/logger\";\nimport { loadEnv } from \"../utils/env\";\n\nexport const serveCommand = new Command(\"serve\")\n .description(\"Start production server (headless, no UI)\")\n .option(\"--port <number>\", \"Server port (env: PDFN_PORT)\", \"3456\")\n .option(\"--max-concurrent <number>\", \"Max concurrent pages (env: PDFN_MAX_CONCURRENT)\", \"5\")\n .option(\"--timeout <ms>\", \"Request timeout in ms (env: PDFN_TIMEOUT)\", \"30000\")\n .option(\"--mode <mode>\", \"Environment mode (loads .env.[mode])\", \"production\")\n .action(async (options) => {\n // Load environment variables based on mode (Vite pattern)\n loadEnv(options.mode);\n\n const port = parseInt(options.port, 10);\n const maxConcurrent = parseInt(options.maxConcurrent, 10);\n const timeout = parseInt(options.timeout, 10);\n\n const server = createServer({ port, maxConcurrent, timeout });\n\n // Handle graceful shutdown\n const shutdown = async () => {\n logger.shutdown();\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n\n await server.start();\n });\n","import type { PdfResult } from \"../server/pdf\";\n\n/**\n * Simple logger with colors and formatting for CLI output\n */\n\n// ANSI color codes\nconst colors = {\n reset: \"\\x1b[0m\",\n dim: \"\\x1b[2m\",\n bold: \"\\x1b[1m\",\n\n // Foreground\n black: \"\\x1b[30m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n gray: \"\\x1b[90m\",\n\n // Background\n bgGreen: \"\\x1b[42m\",\n bgYellow: \"\\x1b[43m\",\n bgRed: \"\\x1b[41m\",\n bgCyan: \"\\x1b[46m\",\n} as const;\n\n// Color helper functions\nconst c = {\n dim: (s: string) => `${colors.dim}${s}${colors.reset}`,\n bold: (s: string) => `${colors.bold}${s}${colors.reset}`,\n green: (s: string) => `${colors.green}${s}${colors.reset}`,\n red: (s: string) => `${colors.red}${s}${colors.reset}`,\n yellow: (s: string) => `${colors.yellow}${s}${colors.reset}`,\n blue: (s: string) => `${colors.blue}${s}${colors.reset}`,\n cyan: (s: string) => `${colors.cyan}${s}${colors.reset}`,\n gray: (s: string) => `${colors.gray}${s}${colors.reset}`,\n magenta: (s: string) => `${colors.magenta}${s}${colors.reset}`,\n};\n\nfunction timestamp(): string {\n return c.dim(new Date().toLocaleTimeString(\"en-US\", { hour12: false }));\n}\n\nfunction formatMs(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`;\n return `${(ms / 1000).toFixed(2)}s`;\n}\n\nexport const logger = {\n /**\n * Log info message\n */\n info: (message: string, ...args: unknown[]) => {\n console.log(`${timestamp()} ${c.cyan(\"ℹ\")} ${message}`, ...args);\n },\n\n /**\n * Log success message\n */\n success: (message: string, ...args: unknown[]) => {\n console.log(`${timestamp()} ${c.green(\"✓\")} ${message}`, ...args);\n },\n\n /**\n * Log warning message\n */\n warn: (message: string, ...args: unknown[]) => {\n console.log(`${timestamp()} ${c.yellow(\"⚠\")} ${c.yellow(message)}`, ...args);\n },\n\n /**\n * Log error message\n */\n error: (message: string, ...args: unknown[]) => {\n console.error(`${timestamp()} ${c.red(\"✗\")} ${c.red(message)}`, ...args);\n },\n\n /**\n * Log HTTP request\n */\n request: (\n method: string,\n path: string,\n status: number,\n duration: number,\n extra?: string\n ) => {\n const methodColor =\n method === \"GET\" ? c.green : method === \"POST\" ? c.cyan : c.yellow;\n const statusColor =\n status >= 500\n ? c.red\n : status >= 400\n ? c.yellow\n : status >= 300\n ? c.blue\n : c.green;\n\n const line = [\n timestamp(),\n methodColor(method.padEnd(4)),\n path,\n statusColor(status.toString()),\n c.dim(formatMs(duration)),\n extra ? c.dim(extra) : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n console.log(line);\n },\n\n /**\n * Log server startup banner\n */\n banner: (port: number, maxConcurrent: number, timeout: number) => {\n console.log();\n console.log(` ${c.bold(\"pdfn serve\")}`);\n console.log();\n console.log(` ${c.green(\"✓\")} Ready at ${c.cyan(`http://localhost:${port}`)}`);\n console.log(` ${c.dim(`${maxConcurrent} concurrent | ${formatMs(timeout)} timeout`)}`);\n console.log();\n console.log(` ${c.dim(\"Endpoints:\")}`);\n console.log(` ${c.green(\"POST\")} /generate ${c.dim(\"HTML → PDF\")}`);\n console.log(` ${c.blue(\"GET\")} /health ${c.dim(\"Health check\")}`);\n console.log();\n },\n\n /**\n * Log PDF details (pages, assets, timing) on a single line\n * Used after the request line has been logged\n */\n pdfDetails: (result: PdfResult) => {\n const { metrics, assets, warnings } = result;\n\n // Build details line: pages • assets • timing (all separated by •)\n const pageStr = `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`;\n\n const images = assets.filter((a) => a.type === \"image\");\n const fonts = assets.filter((a) => a.type === \"font\");\n const assetParts: string[] = [];\n if (images.length > 0) assetParts.push(`${images.length} image${images.length > 1 ? \"s\" : \"\"}`);\n if (fonts.length > 0) assetParts.push(`${fonts.length} font${fonts.length > 1 ? \"s\" : \"\"}`);\n const assetStr = assetParts.length > 0 ? assetParts.join(\" • \") + \" • \" : \"\";\n\n const timingStr = `load ${metrics.contentLoad}ms • paginate ${metrics.pagedJs}ms • capture ${metrics.pdfCapture}ms`;\n\n console.log(c.dim(` ${pageStr} • ${assetStr}${timingStr}`));\n\n // Warnings\n for (const w of warnings) {\n console.log(` ${c.yellow(\"⚠\")} ${c.yellow(w)}`);\n }\n },\n\n /**\n * Log PDF generation metrics (simple format for inline use)\n */\n pdf: (metrics: {\n total: number;\n contentLoad: number;\n pagedJs: number;\n pdfCapture: number;\n pageCount: number;\n }) => {\n const parts = [\n `${metrics.pageCount} ${metrics.pageCount === 1 ? \"page\" : \"pages\"}`,\n formatMs(metrics.total),\n c.dim(\n `(load: ${formatMs(metrics.contentLoad)}, paged: ${formatMs(metrics.pagedJs)}, pdf: ${formatMs(metrics.pdfCapture)})`\n ),\n ];\n return parts.join(\" \");\n },\n\n /**\n * Log browser status\n */\n browser: (status: \"launching\" | \"ready\" | \"disconnected\" | \"closed\") => {\n switch (status) {\n case \"launching\":\n logger.info(\"Initializing...\");\n break;\n case \"ready\":\n logger.success(\"Ready\");\n break;\n case \"disconnected\":\n logger.warn(\"PDF engine disconnected, will restart on next request\");\n break;\n case \"closed\":\n logger.info(\"Shutting down...\");\n break;\n }\n },\n\n /**\n * Log shutdown\n */\n shutdown: () => {\n console.log();\n logger.info(\"Shutting down...\");\n },\n\n // Raw color helpers for custom formatting\n c,\n};\n","import type { Express, Request, Response } from \"express\";\nimport { createBaseServer } from \"./base\";\nimport { logger } from \"../utils/logger\";\n\nexport interface ServerOptions {\n /** Server port (default: env.PDFN_PORT || 3456) */\n port?: number;\n /** Max concurrent pages (default: env.PDFN_MAX_CONCURRENT || 5) */\n maxConcurrent?: number;\n /** Request timeout in ms (default: env.PDFN_TIMEOUT || 30000) */\n timeout?: number;\n}\n\nexport interface PDFNServer {\n app: Express;\n start: () => Promise<void>;\n stop: () => Promise<void>;\n}\n\n/**\n * Create a PDFN server instance\n *\n * Configuration priority: options > environment variables > defaults\n *\n * Environment variables:\n * - PDFN_PORT: Server port (default: 3456)\n * - PDFN_MAX_CONCURRENT: Max concurrent pages (default: 5)\n * - PDFN_TIMEOUT: Request timeout in ms (default: 30000)\n *\n * @example\n * ```ts\n * import { createServer } from 'pdfn/server';\n *\n * const server = createServer({ port: 3456, maxConcurrent: 10 });\n * await server.start();\n * ```\n */\nexport function createServer(options: ServerOptions = {}): PDFNServer {\n const port =\n options.port ?? parseInt(process.env.PDFN_PORT ?? \"3456\", 10);\n\n // Create base server with shared middleware and routes\n const { app, browserManager, maxConcurrent, timeout } = createBaseServer({\n maxConcurrent: options.maxConcurrent,\n timeout: options.timeout,\n enableLogging: true,\n onRequest: (method, path, status, duration, extra) => {\n logger.request(method, path, status, duration, extra);\n },\n onPdfResult: (result) => {\n logger.pdfDetails(result);\n },\n onError: (message) => {\n if (message.includes(\"Server busy\")) {\n logger.warn(`Rate limited: ${browserManager.getActivePages()}/${maxConcurrent} pages in use`);\n } else {\n logger.error(`PDF generation failed: ${message}`);\n }\n },\n });\n\n let server: ReturnType<typeof app.listen> | null = null;\n\n // Landing page - helpful message for browser visitors\n app.get(\"/\", (_req: Request, res: Response) => {\n res.type(\"text/plain\").send(`PDFN Server\n\nThis is a headless API server for PDF generation.\n\nEndpoints:\n POST /generate Generate PDF from HTML\n GET /health Health check\n\nUsage:\n curl -X POST http://localhost:${port}/generate \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"html\": \"<html>...</html>\"}' \\\\\n -o output.pdf\n\nFor development with live preview, use:\n npx pdfn dev\n`);\n });\n\n return {\n app,\n start: async () => {\n // Pre-launch browser\n logger.browser(\"launching\");\n await browserManager.getBrowser();\n logger.browser(\"ready\");\n\n return new Promise((resolve, reject) => {\n server = app.listen(port, () => {\n logger.banner(port, maxConcurrent, timeout);\n resolve();\n });\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n logger.error(`Port ${port} is already in use`);\n logger.info(`Either stop the existing server or use a different port`);\n process.exit(1);\n }\n reject(err);\n });\n });\n },\n stop: async () => {\n await browserManager.close();\n logger.browser(\"closed\");\n\n if (server) {\n await new Promise<void>((resolve) => {\n server!.close(() => resolve());\n });\n server = null;\n }\n\n logger.success(\"Server stopped\");\n },\n };\n}\n\n// Re-export types\nexport type { PdfGenerationOptions, PdfResult } from \"./pdf\";\nexport type { BrowserManagerOptions } from \"./browser\";\nexport { createBaseServer, type BaseServerOptions, type BaseServer } from \"./base\";\n","import { Command } from \"commander\";\nimport { existsSync, mkdirSync, copyFileSync, readFileSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport chalk from \"chalk\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Available templates with descriptions\nconst TEMPLATES: Record<string, { name: string; description: string; pageSize: string }> = {\n invoice: {\n name: \"Invoice\",\n description: \"Professional invoice with itemized billing\",\n pageSize: \"A4\",\n },\n letter: {\n name: \"Business Letter\",\n description: \"US business correspondence\",\n pageSize: \"Letter\",\n },\n contract: {\n name: \"Contract\",\n description: \"Legal service agreement with terms\",\n pageSize: \"Legal\",\n },\n ticket: {\n name: \"Event Ticket\",\n description: \"Admission ticket with QR placeholder\",\n pageSize: \"A5\",\n },\n poster: {\n name: \"Poster\",\n description: \"Event poster (landscape)\",\n pageSize: \"Tabloid\",\n },\n};\n\ntype TemplateStyle = \"inline\" | \"tailwind\";\n\nfunction getTemplatesDir(style: TemplateStyle): string {\n // After build, cli.js is in dist/, templates are in templates/\n // So from dist/ we go up one level to package root, then into templates/<style>/\n return join(__dirname, \"..\", \"templates\", style);\n}\n\n/**\n * Check if @pdfn/tailwind is installed in user's project\n * Checks both package.json and node_modules for compatibility with npm, pnpm, yarn\n */\nfunction isTailwindInstalled(cwd: string): boolean {\n // First check package.json for explicit dependency\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n if (pkg.dependencies?.[\"@pdfn/tailwind\"] || pkg.devDependencies?.[\"@pdfn/tailwind\"]) {\n return true;\n }\n }\n } catch {\n // Ignore parse errors\n }\n\n // Fall back to checking node_modules (for linked packages, global installs, etc.)\n const tailwindPath = join(cwd, \"node_modules\", \"@pdfn\", \"tailwind\");\n return existsSync(tailwindPath);\n}\n\nexport const addCommand = new Command(\"add\")\n .description(\"Add a starter template to your project\")\n .argument(\"[template]\", \"Template name (e.g., invoice, letter, contract)\")\n .option(\"--list\", \"List available templates\")\n .option(\"--tailwind\", \"Use Tailwind CSS styling (requires @pdfn/tailwind)\")\n .option(\"--inline\", \"Use inline styles (default)\")\n .option(\"--output <path>\", \"Output directory\", \"./pdf-templates\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (template, options) => {\n const cwd = process.cwd();\n\n // List templates\n if (options.list || !template) {\n console.log(chalk.bold(\"\\nAvailable templates:\\n\"));\n\n for (const [id, info] of Object.entries(TEMPLATES)) {\n console.log(` ${chalk.cyan(id.padEnd(12))} ${info.description} ${chalk.dim(`(${info.pageSize})`)}`);\n }\n\n console.log(chalk.dim(\"\\nUsage: pdfn add <template> [--tailwind]\"));\n console.log(chalk.dim(\"Example: pdfn add invoice\"));\n console.log(chalk.dim(\"Example: pdfn add invoice --tailwind\\n\"));\n console.log(chalk.bold(\"Options:\"));\n console.log(chalk.dim(\" --inline Use inline styles (default)\"));\n console.log(chalk.dim(\" --tailwind Use Tailwind CSS (requires @pdfn/tailwind)\\n\"));\n return;\n }\n\n // Validate template\n if (!TEMPLATES[template]) {\n console.error(chalk.red(`\\nError: Unknown template \"${template}\"`));\n console.log(chalk.dim(\"Run 'pdfn add --list' to see available templates\\n\"));\n process.exit(1);\n }\n\n // Determine style (default to inline)\n const style: TemplateStyle = options.tailwind ? \"tailwind\" : \"inline\";\n\n // Check for @pdfn/tailwind if tailwind style requested\n if (style === \"tailwind\" && !isTailwindInstalled(cwd)) {\n console.error(chalk.yellow(`\\n⚠ @pdfn/tailwind is not installed.`));\n console.log(chalk.dim(\"Install it first to use Tailwind templates:\\n\"));\n console.log(chalk.cyan(\" npm install @pdfn/tailwind\\n\"));\n console.log(chalk.dim(\"Or use inline styles (default):\\n\"));\n console.log(chalk.cyan(` pdfn add ${template}\\n`));\n process.exit(1);\n }\n\n const templatesDir = getTemplatesDir(style);\n const sourceFile = join(templatesDir, `${template}.tsx`);\n const outputDir = options.output;\n const outputFile = join(outputDir, `${template}.tsx`);\n\n // Check if source template exists\n if (!existsSync(sourceFile)) {\n console.error(chalk.red(`\\nError: Template file not found: ${sourceFile}`));\n console.log(chalk.dim(\"This may be a package installation issue.\\n\"));\n process.exit(1);\n }\n\n // Create output directory\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n console.log(chalk.dim(`Created ${outputDir}/`));\n }\n\n // Check if file already exists\n if (existsSync(outputFile) && !options.force) {\n console.error(chalk.yellow(`\\nFile already exists: ${outputFile}`));\n console.log(chalk.dim(\"Use --force to overwrite\\n\"));\n process.exit(1);\n }\n\n // Copy template\n try {\n copyFileSync(sourceFile, outputFile);\n\n const info = TEMPLATES[template];\n const styleLabel = style === \"tailwind\" ? chalk.cyan(\" (Tailwind)\") : chalk.dim(\" (inline styles)\");\n console.log(chalk.green(`\\n✓ Added ${info.name} template`) + styleLabel);\n console.log(chalk.dim(` ${outputFile}\\n`));\n\n // Show next steps\n console.log(chalk.bold(\"Next steps:\"));\n console.log(chalk.dim(` 1. Edit ${outputFile} to customize`));\n console.log(chalk.dim(` 2. Run 'npx pdfn dev' to preview\\n`));\n\n // Additional info for tailwind\n if (style === \"tailwind\") {\n console.log(chalk.dim(\"Note: Tailwind templates require @pdfn/tailwind to be installed.\\n\"));\n }\n } catch (error) {\n console.error(chalk.red(`\\nError copying template: ${error}`));\n process.exit(1);\n }\n });\n\n// Also export the template info for use by dev server\nexport { TEMPLATES };\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAseD,UAAU,SAAS,IACf,eACA,uFACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YA8BM,iBACI,kGACA,+GACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BA8FkB,iBAAiB,IAAI,cAAc,MAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["Command","existsSync","resolve","puppeteer","startTime","existsSync","config","resolve","options","puppeteer","Command","resolve","Command","Command","existsSync","readFileSync","join","chalk","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/dev.ts","../src/server/base.ts","../src/server/browser.ts","../src/utils/debug.ts","../src/server/pdf.ts","../src/server/routes.ts","../src/utils/env.ts","../src/commands/serve.ts","../src/utils/logger.ts","../src/server/index.ts","../src/commands/add.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { devCommand } from \"./commands/dev.js\";\nimport { serveCommand } from \"./commands/serve.js\";\nimport { addCommand } from \"./commands/add.js\";\n\nconst program = new Command()\n .name(\"pdfn\")\n .description(\"PDFN CLI - PDF generation from React components\")\n .version(\"0.0.1-alpha.1\");\n\nprogram.addCommand(devCommand);\nprogram.addCommand(serveCommand);\nprogram.addCommand(addCommand);\n\nprogram.parse();\n","import { Command } from \"commander\";\nimport { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport type { Request, Response } from \"express\";\nimport { createServer as createViteServer } from \"vite\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport chokidar from \"chokidar\";\nimport { createServer as createHttpServer } from \"http\";\nimport { spawn } from \"child_process\";\nimport puppeteer from \"puppeteer\";\nimport { createBaseServer } from \"../server/base\";\nimport { generatePdf } from \"../server/pdf\";\nimport type { DebugOptions } from \"@pdfn/react\";\nimport { pdfnTailwind } from \"@pdfn/vite\";\nimport chalk from \"chalk\";\nimport { loadEnv } from \"../utils/env\";\n\ninterface TemplateInfo {\n id: string;\n name: string;\n file: string;\n path: string;\n sampleData?: Record<string, unknown>;\n}\n\n/**\n * Standardized templates directory (convention over configuration)\n */\nconst TEMPLATES_DIR = \"./pdfn-templates\";\n\ninterface DevServerOptions {\n port: number;\n open: boolean;\n mode: string;\n}\n\nasync function scanTemplates(templatesDir: string): Promise<TemplateInfo[]> {\n if (!existsSync(templatesDir)) {\n return [];\n }\n\n // Try to load config file with sample data\n let configData: Record<string, Record<string, unknown>> = {};\n const configPaths = [\n join(process.cwd(), \"src\", \"config\", \"templates.json\"),\n join(process.cwd(), \"templates.json\"),\n join(templatesDir, \"templates.json\"),\n ];\n\n for (const configPath of configPaths) {\n if (existsSync(configPath)) {\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (config.templates && Array.isArray(config.templates)) {\n for (const t of config.templates) {\n if (t.id && t.sampleData) {\n configData[t.id] = t.sampleData;\n }\n }\n }\n break;\n } catch {\n // Ignore config parse errors\n }\n }\n }\n\n const files = readdirSync(templatesDir).filter((f) => f.endsWith(\".tsx\"));\n\n // Filter to only include files that look like templates\n // (have \"export default function\" or similar patterns)\n const templates: TemplateInfo[] = [];\n\n for (const file of files) {\n const id = file.replace(\".tsx\", \"\");\n const filePath = join(templatesDir, file);\n\n // Quick check: read file and look for default export pattern\n try {\n const content = readFileSync(filePath, \"utf-8\");\n // Must have a default export that looks like a component\n if (!content.includes(\"export default\") || !content.includes(\"function\")) {\n continue;\n }\n // Skip files that are clearly not templates (no Document/Page imports)\n if (!content.includes(\"Document\") && !content.includes(\"Page\")) {\n continue;\n }\n } catch {\n continue;\n }\n\n // Convert kebab/snake case to Title Case\n const name = id\n .split(/[-_]/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \");\n\n templates.push({\n id,\n name,\n file,\n path: filePath,\n sampleData: configData[id],\n });\n }\n\n return templates;\n}\n\nfunction createPreviewHTML(templates: TemplateInfo[], activeTemplate: string | null): string {\n const templateList = templates\n .map(\n (t) => `\n <button\n class=\"template-btn ${t.id === activeTemplate ? \"active\" : \"\"}\"\n data-template=\"${t.id}\"\n data-file=\"${t.file}\"\n >\n <span class=\"template-name\">${t.name}</span>\n </button>\n `\n )\n .join(\"\");\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>PDFN Dev Server</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n :root {\n --primary: #22d3ee;\n --primary-hover: #06b6d4;\n --bg: #0a0a0a;\n --surface-1: #111;\n --surface-2: #1a1a1a;\n --border: #222;\n --text: #fafafa;\n --text-muted: #666;\n --text-secondary: #888;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--bg);\n color: var(--text);\n min-height: 100vh;\n }\n\n .header {\n background: var(--surface-1);\n border-bottom: 1px solid var(--border);\n padding: 12px 24px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .logo {\n font-size: 20px;\n font-weight: 800;\n letter-spacing: -0.5px;\n }\n\n .logo span { color: var(--primary); }\n\n .status {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #22c55e;\n }\n\n .status-dot.disconnected { background: #ef4444; }\n\n .container {\n display: flex;\n height: calc(100vh - 57px);\n }\n\n .main-wrapper {\n flex: 1;\n display: flex;\n overflow: hidden;\n }\n\n .sidebar {\n width: 200px;\n background: var(--surface-1);\n border-right: 1px solid var(--border);\n padding: 16px;\n overflow-y: auto;\n }\n\n .sidebar-title {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text-muted);\n margin-bottom: 12px;\n }\n\n .template-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 12px;\n background: transparent;\n border: 1px solid #333;\n border-radius: 6px;\n color: #ccc;\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n margin-bottom: 8px;\n transition: all 0.15s;\n }\n\n .template-btn:hover {\n background: var(--surface-2);\n border-color: #444;\n }\n\n .template-btn.active {\n background: rgba(34, 211, 238, 0.1);\n border-color: var(--primary);\n color: var(--primary);\n }\n\n .template-name { font-weight: 500; }\n\n .main {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* Context bar - top */\n .context-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px;\n background: var(--surface-1);\n border-bottom: 1px solid var(--border);\n }\n\n .context-left {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .file-name {\n font-family: ui-monospace, SFMono-Regular, monospace;\n font-size: 13px;\n color: var(--text);\n font-weight: 500;\n }\n\n .file-name:empty::after {\n content: \"Select a template\";\n color: var(--text-muted);\n font-style: italic;\n font-family: inherit;\n }\n\n .page-info {\n font-size: 12px;\n color: var(--text-muted);\n }\n\n .context-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n /* Preview area */\n .preview-area {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #27272a;\n overflow: hidden;\n padding: 24px;\n }\n\n .preview-frame {\n background: #fff;\n border-radius: 4px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\n overflow: hidden;\n transition: opacity 0.2s;\n }\n\n .preview-frame.loading { opacity: 0.4; }\n\n .preview-frame iframe {\n display: block;\n border: none;\n }\n\n .empty-state {\n text-align: center;\n color: var(--text-muted);\n }\n\n .empty-state h2 {\n font-size: 18px;\n margin-bottom: 8px;\n color: var(--text-secondary);\n }\n\n .empty-state p {\n font-size: 14px;\n margin-bottom: 16px;\n }\n\n .empty-state code {\n background: var(--surface-2);\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 13px;\n }\n\n .loading-spinner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--text-muted);\n }\n\n .spinner {\n width: 32px;\n height: 32px;\n border: 2px solid #333;\n border-top-color: var(--primary);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Inspector panel - right side */\n .inspector-panel {\n width: 200px;\n background: var(--surface-1);\n border-left: 1px solid var(--border);\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n }\n\n .inspector-title {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text);\n padding: 12px 16px;\n border-bottom: 1px solid var(--border);\n }\n\n .inspector-content {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n .inspector-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .inspector-section-title {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text-muted);\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .metrics-note {\n font-size: 10px;\n color: var(--text-muted);\n margin-top: 8px;\n font-style: italic;\n }\n\n /* Metrics display */\n .metrics-grid {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .metric-item {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n }\n\n .metric-label {\n font-size: 12px;\n color: var(--text-muted);\n }\n\n .metric-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--primary);\n font-variant-numeric: tabular-nums;\n }\n\n /* Overlay checkboxes */\n .overlay-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .overlay-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .overlay-checkbox:hover {\n color: var(--text);\n }\n\n .overlay-checkbox input {\n appearance: none;\n width: 16px;\n height: 16px;\n border: 1px solid #444;\n border-radius: 3px;\n background: var(--surface-2);\n cursor: pointer;\n position: relative;\n flex-shrink: 0;\n }\n\n .overlay-checkbox input:hover {\n border-color: #555;\n }\n\n .overlay-checkbox input:checked {\n background: var(--primary);\n border-color: var(--primary);\n }\n\n .overlay-checkbox input:checked::after {\n content: \"\";\n position: absolute;\n left: 5px;\n top: 2px;\n width: 4px;\n height: 8px;\n border: solid #000;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .debug-link {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 8px;\n font-size: 12px;\n color: var(--text-muted);\n text-decoration: none;\n transition: color 0.15s;\n }\n\n .debug-link:hover {\n color: var(--primary);\n }\n\n .debug-link svg {\n opacity: 0.7;\n }\n\n /* Console section */\n .console-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n user-select: none;\n }\n\n .console-header:hover {\n color: var(--text-secondary);\n }\n\n .console-toggle {\n transition: transform 0.2s;\n }\n\n .console-toggle.collapsed {\n transform: rotate(-90deg);\n }\n\n .console-content {\n font-size: 12px;\n }\n\n .console-empty {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--text-muted);\n }\n\n .console-empty svg {\n color: #22c55e;\n }\n\n .console-message {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n padding: 4px 0;\n }\n\n .console-message.error {\n color: #ef4444;\n }\n\n .console-message.warning {\n color: #eab308;\n }\n\n .console-message-icon {\n flex-shrink: 0;\n }\n\n .console-message-text {\n word-break: break-all;\n }\n\n /* Buttons */\n .btn {\n padding: 6px 10px;\n background: var(--surface-2);\n border: 1px solid #333;\n border-radius: 5px;\n color: #ccc;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.15s;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n }\n\n .btn:hover { background: #333; border-color: #444; }\n\n .btn-primary {\n background: var(--primary);\n border-color: var(--primary);\n color: #000;\n font-weight: 600;\n }\n\n .btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }\n </style>\n</head>\n<body>\n <header class=\"header\">\n <div class=\"logo\">pdf<span>n</span> <span style=\"font-weight: 400; color: var(--text-muted); font-size: 14px; margin-left: 8px;\">dev</span></div>\n <div class=\"status\">\n <div class=\"status-dot\" id=\"status-dot\"></div>\n <span id=\"status-text\">Connected</span>\n </div>\n </header>\n\n <div class=\"container\">\n <aside class=\"sidebar\">\n <div class=\"sidebar-title\">Templates</div>\n ${\n templates.length > 0\n ? templateList\n : '<div class=\"empty-state\"><p>No templates found</p><code>pdfn add invoice</code></div>'\n }\n </aside>\n\n <div class=\"main-wrapper\">\n <main class=\"main\">\n <!-- Context bar: filename + page info + actions -->\n <div class=\"context-bar\">\n <div class=\"context-left\">\n <div class=\"file-name\" id=\"file-name\"></div>\n <div class=\"page-info\" id=\"page-info\"></div>\n </div>\n <div class=\"context-actions\">\n <a class=\"btn\" id=\"view-pdf\" href=\"#\" target=\"_blank\" title=\"View PDF in browser\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"/>\n </svg>\n View PDF\n </a>\n <button class=\"btn btn-primary\" id=\"download-pdf\" title=\"Download PDF\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"/>\n </svg>\n Download\n </button>\n </div>\n </div>\n\n <!-- Preview area -->\n <div class=\"preview-area\" id=\"preview-area\">\n ${\n activeTemplate\n ? '<div class=\"loading-spinner\"><div class=\"spinner\"></div><span>Loading preview...</span></div>'\n : '<div class=\"empty-state\"><h2>Select a template</h2><p>Choose a template from the sidebar to preview</p></div>'\n }\n </div>\n </main>\n\n <!-- Inspector panel: right side -->\n <aside class=\"inspector-panel\" id=\"inspector-panel\">\n <div class=\"inspector-title\">Inspector</div>\n <div class=\"inspector-content\">\n <div class=\"inspector-section\">\n <div class=\"inspector-section-title\">Performance</div>\n <div class=\"metrics-grid\">\n <div class=\"metric-item\">\n <div class=\"metric-label\">Render</div>\n <div class=\"metric-value\" id=\"metric-render\">--</div>\n </div>\n <div class=\"metric-item\">\n <div class=\"metric-label\">Pagination</div>\n <div class=\"metric-value\" id=\"metric-pagination\">--</div>\n </div>\n <div class=\"metric-item\">\n <div class=\"metric-label\">Pages</div>\n <div class=\"metric-value\" id=\"metric-pages\">--</div>\n </div>\n </div>\n <div class=\"metrics-note\">Measured in browser. Times vary on server.</div>\n </div>\n\n <div class=\"inspector-section\">\n <div class=\"inspector-section-title\">Debug</div>\n <div class=\"overlay-list\">\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-grid\">\n Grid (1cm)\n </label>\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-margins\">\n Margins\n </label>\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-headers\">\n Headers/Footers\n </label>\n <label class=\"overlay-checkbox\">\n <input type=\"checkbox\" id=\"overlay-breaks\">\n Page numbers\n </label>\n </div>\n <a class=\"debug-link\" id=\"view-html\" href=\"#\" target=\"_blank\">\n View HTML\n <svg width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"/>\n </svg>\n </a>\n </div>\n\n <div class=\"inspector-section\">\n <div class=\"inspector-section-title console-header\" id=\"console-header\">\n <span>Console</span>\n <svg class=\"console-toggle\" id=\"console-toggle\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"/>\n </svg>\n </div>\n <div class=\"console-content\" id=\"console-content\">\n <div class=\"console-empty\" id=\"console-empty\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"/>\n </svg>\n No issues\n </div>\n <div id=\"console-messages\" style=\"display: none;\"></div>\n </div>\n </div>\n </div>\n </aside>\n </div>\n </div>\n\n <script>\n // Page sizes in points (72 dpi)\n const PAGE_SIZES = {\n A3: { width: 842, height: 1191 },\n A4: { width: 595, height: 842 },\n A5: { width: 420, height: 595 },\n B4: { width: 709, height: 1001 },\n B5: { width: 499, height: 709 },\n Letter: { width: 612, height: 792 },\n Legal: { width: 612, height: 1008 },\n Tabloid: { width: 792, height: 1224 },\n };\n\n const PT_TO_PX = 96 / 72;\n const STORAGE_KEY = 'pdfn-inspector';\n\n let ws;\n let currentTemplate = ${activeTemplate ? `\"${activeTemplate}\"` : \"null\"};\n let templateInfo = {};\n\n // Inspector state with defaults (all overlays off by default)\n let inspectorState = {\n overlays: {\n grid: false,\n margins: false,\n headers: false,\n breaks: false,\n },\n consoleExpanded: true\n };\n\n // Console messages\n let consoleMessages = [];\n\n // Load state from localStorage\n function loadState() {\n try {\n const saved = localStorage.getItem(STORAGE_KEY);\n if (saved) {\n const parsed = JSON.parse(saved);\n inspectorState = { ...inspectorState, ...parsed };\n }\n } catch (e) {}\n }\n\n // Save state to localStorage\n function saveState() {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(inspectorState));\n } catch (e) {}\n }\n\n // Apply state to UI\n function applyState() {\n // Overlay checkboxes\n document.getElementById('overlay-grid').checked = inspectorState.overlays.grid;\n document.getElementById('overlay-margins').checked = inspectorState.overlays.margins;\n document.getElementById('overlay-headers').checked = inspectorState.overlays.headers;\n document.getElementById('overlay-breaks').checked = inspectorState.overlays.breaks;\n\n // Console state\n const consoleContent = document.getElementById('console-content');\n const consoleToggle = document.getElementById('console-toggle');\n if (inspectorState.consoleExpanded) {\n consoleContent.style.display = 'block';\n consoleToggle.classList.remove('collapsed');\n } else {\n consoleContent.style.display = 'none';\n consoleToggle.classList.add('collapsed');\n }\n }\n\n // Toggle console expanded state\n function toggleConsole() {\n inspectorState.consoleExpanded = !inspectorState.consoleExpanded;\n saveState();\n applyState();\n }\n\n // Add console message\n function addConsoleMessage(type, message) {\n consoleMessages.push({ type, message });\n renderConsoleMessages();\n }\n\n // Clear console messages\n function clearConsoleMessages() {\n consoleMessages = [];\n renderConsoleMessages();\n }\n\n // Render console messages\n function renderConsoleMessages() {\n const emptyEl = document.getElementById('console-empty');\n const messagesEl = document.getElementById('console-messages');\n\n if (consoleMessages.length === 0) {\n emptyEl.style.display = 'flex';\n messagesEl.style.display = 'none';\n messagesEl.innerHTML = '';\n } else {\n emptyEl.style.display = 'none';\n messagesEl.style.display = 'block';\n messagesEl.innerHTML = consoleMessages.map(msg =>\n \\`<div class=\"console-message \\${msg.type}\">\n <span class=\"console-message-icon\">\\${msg.type === 'error' ? '✗' : '⚠'}</span>\n <span class=\"console-message-text\">\\${escapeHtml(msg.message)}</span>\n </div>\\`\n ).join('');\n }\n }\n\n // Escape HTML\n function escapeHtml(text) {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n // Get debug query string from overlay state\n function getDebugQuery() {\n const { overlays } = inspectorState;\n const hasAny = Object.values(overlays).some(v => v);\n if (!hasAny) return '';\n\n const params = new URLSearchParams();\n if (overlays.grid) params.set('grid', '1');\n if (overlays.margins) params.set('margins', '1');\n if (overlays.headers) params.set('headers', '1');\n if (overlays.breaks) params.set('breaks', '1');\n\n return '?' + params.toString();\n }\n\n // Check if any overlay is enabled\n function hasAnyOverlay() {\n return Object.values(inspectorState.overlays).some(v => v);\n }\n\n loadState();\n\n function connect() {\n ws = new WebSocket('ws://' + location.host);\n\n ws.onopen = () => {\n document.getElementById('status-dot').classList.remove('disconnected');\n document.getElementById('status-text').textContent = 'Connected';\n };\n\n ws.onclose = () => {\n document.getElementById('status-dot').classList.add('disconnected');\n document.getElementById('status-text').textContent = 'Disconnected';\n setTimeout(connect, 2000);\n };\n\n ws.onmessage = (event) => {\n const data = JSON.parse(event.data);\n if (data.type === 'reload') {\n if (currentTemplate) loadPreview(currentTemplate);\n } else if (data.type === 'templates') {\n updateTemplateList(data.templates);\n }\n };\n }\n\n connect();\n\n // Update template list in sidebar (called when templates are added/removed)\n function updateTemplateList(templates) {\n const sidebar = document.querySelector('.sidebar');\n const titleEl = sidebar.querySelector('.sidebar-title');\n\n // Clear existing buttons\n sidebar.innerHTML = '';\n sidebar.appendChild(titleEl);\n\n if (templates.length === 0) {\n sidebar.innerHTML += '<div class=\"empty-state\"><p>No templates found</p><code>pdfn add invoice</code></div>';\n // Clear preview if no templates\n currentTemplate = null;\n document.getElementById('file-name').textContent = '';\n document.getElementById('page-info').textContent = '';\n document.getElementById('preview-area').innerHTML = '<div class=\"empty-state\"><h2>No templates</h2><p>Add a template to get started</p><code>pdfn add invoice</code></div>';\n return;\n }\n\n // Add template buttons\n templates.forEach(t => {\n const btn = document.createElement('button');\n btn.className = 'template-btn' + (t.id === currentTemplate ? ' active' : '');\n btn.dataset.template = t.id;\n btn.dataset.file = t.file;\n btn.innerHTML = '<span class=\"template-name\">' + t.name + '</span>';\n btn.addEventListener('click', () => loadPreview(t.id));\n sidebar.appendChild(btn);\n });\n\n // If current template was deleted, switch to first template\n const templateIds = templates.map(t => t.id);\n if (currentTemplate && !templateIds.includes(currentTemplate)) {\n loadPreview(templates[0].id);\n }\n }\n\n // Listen for metrics from iframe (postMessage from PDFN script)\n window.addEventListener('message', function(event) {\n if (event.data && event.data.type === 'pdfn:metrics') {\n const metrics = event.data.metrics;\n if (metrics.paginationTime !== undefined) {\n document.getElementById('metric-pagination').textContent = metrics.paginationTime + 'ms';\n }\n if (metrics.pages !== undefined) {\n document.getElementById('metric-pages').textContent = metrics.pages;\n }\n }\n });\n\n function detectPageInfo(html) {\n let pageSize = 'A4';\n let orientation = 'portrait';\n\n // Check for size attribute\n const sizeMatch = html.match(/size=\"([^\"]+)\"/i) || html.match(/data-page-size=\"([^\"]+)\"/i);\n if (sizeMatch) {\n const s = sizeMatch[1];\n if (PAGE_SIZES[s]) pageSize = s;\n }\n\n // Check for orientation attribute\n const orientMatch = html.match(/orientation=\"([^\"]+)\"/i);\n if (orientMatch && orientMatch[1] === 'landscape') {\n orientation = 'landscape';\n }\n\n // Special handling: Tabloid is typically landscape (posters)\n if (html.includes('Tabloid') || html.includes('tabloid')) {\n pageSize = 'Tabloid';\n // Default Tabloid to landscape unless explicitly portrait\n if (!html.includes('orientation=\"portrait\"')) {\n orientation = 'landscape';\n }\n }\n\n return { pageSize, orientation };\n }\n\n function calculateScale(pageSize, orientation) {\n const container = document.getElementById('preview-area');\n const rect = container.getBoundingClientRect();\n const maxWidth = rect.width - 48;\n const maxHeight = rect.height - 48;\n\n const size = PAGE_SIZES[pageSize] || PAGE_SIZES.A4;\n const pageW = (orientation === 'landscape' ? size.height : size.width) * PT_TO_PX;\n const pageH = (orientation === 'landscape' ? size.width : size.height) * PT_TO_PX;\n\n const scale = Math.min(maxWidth / pageW, maxHeight / pageH, 1);\n return { pageW, pageH, scale };\n }\n\n async function loadPreview(templateId) {\n currentTemplate = templateId;\n\n // Get template file name from button\n const activeBtn = document.querySelector('.template-btn[data-template=\"' + templateId + '\"]');\n const fileName = activeBtn ? activeBtn.dataset.file : templateId + '.tsx';\n\n document.querySelectorAll('.template-btn').forEach(btn => {\n btn.classList.toggle('active', btn.dataset.template === templateId);\n });\n\n // Update context bar\n document.getElementById('file-name').textContent = fileName;\n\n const previewArea = document.getElementById('preview-area');\n previewArea.innerHTML = '<div class=\"loading-spinner\"><div class=\"spinner\"></div><span>Rendering...</span></div>';\n\n try {\n const debugQuery = getDebugQuery();\n const htmlRes = await fetch('/api/template/' + templateId + '/html' + debugQuery);\n const html = await htmlRes.text();\n\n templateInfo = detectPageInfo(html);\n document.getElementById('page-info').textContent =\n templateInfo.pageSize + ' · ' + templateInfo.orientation;\n\n // Update metrics (render time from server, pagination from iframe postMessage)\n const renderTime = htmlRes.headers.get('X-Render-Time');\n\n if (renderTime) {\n document.getElementById('metric-render').textContent = renderTime + 'ms';\n }\n\n // Reset pagination metrics (will be updated via postMessage from iframe)\n document.getElementById('metric-pagination').textContent = '--';\n document.getElementById('metric-pages').textContent = '--';\n\n const { pageW, pageH, scale } = calculateScale(templateInfo.pageSize, templateInfo.orientation);\n const displayW = pageW * scale;\n const displayH = pageH * scale;\n\n previewArea.innerHTML = '';\n const frame = document.createElement('div');\n frame.className = 'preview-frame';\n frame.style.width = displayW + 'px';\n frame.style.height = displayH + 'px';\n\n const iframe = document.createElement('iframe');\n iframe.style.width = pageW + 'px';\n iframe.style.height = pageH + 'px';\n iframe.style.transform = 'scale(' + scale + ')';\n iframe.style.transformOrigin = 'top left';\n iframe.srcdoc = html;\n\n frame.classList.add('loading');\n iframe.onload = () => frame.classList.remove('loading');\n\n frame.appendChild(iframe);\n previewArea.appendChild(frame);\n\n // Set up action buttons\n const pdfUrl = '/api/template/' + templateId + '/pdf' + debugQuery;\n const htmlUrl = '/api/template/' + templateId + '/html' + debugQuery;\n\n document.getElementById('view-pdf').href = pdfUrl;\n document.getElementById('view-html').href = htmlUrl;\n\n document.getElementById('download-pdf').onclick = () => {\n const link = document.createElement('a');\n link.href = pdfUrl;\n link.download = templateId + '.pdf';\n link.click();\n };\n\n } catch (err) {\n previewArea.innerHTML = '<div class=\"empty-state\"><h2>Error</h2><p>' + err.message + '</p></div>';\n }\n }\n\n document.querySelectorAll('.template-btn').forEach(btn => {\n btn.addEventListener('click', () => loadPreview(btn.dataset.template));\n });\n\n // Overlay checkbox handlers\n const overlayCheckboxes = ['grid', 'margins', 'headers', 'breaks'];\n overlayCheckboxes.forEach(name => {\n document.getElementById('overlay-' + name).onchange = (e) => {\n inspectorState.overlays[name] = e.target.checked;\n saveState();\n if (currentTemplate) loadPreview(currentTemplate);\n };\n });\n\n // Console header click handler\n document.getElementById('console-header').onclick = toggleConsole;\n\n let resizeTimeout;\n window.addEventListener('resize', () => {\n clearTimeout(resizeTimeout);\n resizeTimeout = setTimeout(() => {\n if (currentTemplate) loadPreview(currentTemplate);\n }, 150);\n });\n\n // Apply saved state and load first template\n applyState();\n ${activeTemplate ? `loadPreview(\"${activeTemplate}\");` : \"\"}\n </script>\n</body>\n</html>`;\n}\n\nasync function startDevServer(options: DevServerOptions) {\n const { port, open, mode } = options;\n const absoluteTemplatesDir = resolve(process.cwd(), TEMPLATES_DIR);\n\n // Show header and initializing message\n console.log(chalk.bold(\"\\n pdfn dev\\n\"));\n console.log(chalk.dim(\" Initializing...\"));\n\n // Scan templates\n let templates = await scanTemplates(absoluteTemplatesDir);\n\n // Show relative path for cleaner output\n const displayPath = TEMPLATES_DIR;\n const templateCount = templates.length === 1 ? \"1 template\" : `${templates.length} templates`;\n\n // Create base server with shared /generate and /health endpoints\n const { app, browserManager } = createBaseServer({\n enableLogging: false, // Dev uses custom logging per route\n onSuccess: (result) => {\n const { metrics } = result;\n console.log(\n chalk.green(\" ✓\"),\n chalk.dim(\"/generate\"),\n chalk.cyan(`${metrics.total}ms`),\n chalk.dim(\"•\"),\n `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`,\n chalk.dim(\"•\"),\n formatBytes(metrics.pdfSize)\n );\n },\n onError: (message) => {\n console.log(chalk.red(\" ✗\"), chalk.dim(\"/generate\"), chalk.red(message));\n },\n });\n const server = createHttpServer(app);\n\n // Create WebSocket server for hot reload\n const wss = new WebSocketServer({ server });\n const clients = new Set<WebSocket>();\n\n wss.on(\"connection\", (ws) => {\n clients.add(ws);\n ws.on(\"close\", () => clients.delete(ws));\n });\n\n wss.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n // Handled by server error handler\n return;\n }\n console.error(chalk.red(\" ✗ WebSocket error:\"), err.message);\n });\n\n function broadcast(message: object) {\n const data = JSON.stringify(message);\n clients.forEach((client) => {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data);\n }\n });\n }\n\n // Create Vite server for template compilation\n // Custom logger to silence Vite's default output (we handle our own logging)\n const viteLogger = {\n info: () => {},\n warn: () => {},\n error: (msg: string) => console.error(chalk.red(\" ✗ Vite:\"), msg),\n warnOnce: () => {},\n hasWarned: false,\n clearScreen: () => {},\n hasErrorLogged: () => false,\n };\n\n const vite = await createViteServer({\n root: process.cwd(),\n mode,\n server: {\n middlewareMode: true,\n hmr: { server } // Use our HTTP server for Vite's WebSocket\n },\n appType: \"custom\",\n customLogger: viteLogger,\n optimizeDeps: {\n include: [\"react\", \"react-dom\"],\n },\n esbuild: {\n jsx: \"automatic\",\n },\n ssr: {\n // Don't externalize these - we need to transform them\n noExternal: [\"@pdfn/react\", \"@pdfn/tailwind\", \"server-only\"],\n },\n plugins: [\n // Pre-compile Tailwind CSS for edge compatibility\n pdfnTailwind({\n templates: [\n join(TEMPLATES_DIR, \"**/*.tsx\"),\n ],\n }),\n {\n name: \"mock-server-only\",\n enforce: \"pre\",\n resolveId(id) {\n if (id === \"server-only\") {\n return { id: \"\\0server-only-mock\", moduleSideEffects: false };\n }\n },\n load(id) {\n if (id === \"\\0server-only-mock\") {\n // Return empty module - we're in SSR context so server-only is fine\n return \"export default {};\";\n }\n },\n },\n ],\n });\n\n\n // Watch for template and CSS changes\n // Watch templates dir and styles.css + styles/ directory for CSS HMR\n const watchPaths = [\n absoluteTemplatesDir,\n join(absoluteTemplatesDir, \"styles.css\"),\n join(absoluteTemplatesDir, \"styles\"),\n ];\n const watcher = chokidar.watch(watchPaths, {\n ignored: /(^|[\\/\\\\])\\../,\n persistent: true,\n });\n\n // Helper to check if a file is a template (matches what we show in sidebar)\n function isTemplateFile(filePath: string): boolean {\n const fileName = filePath.split(\"/\").pop() || \"\";\n // Must be a .tsx file in the root of templates dir (not in subdirectories)\n if (!fileName.endsWith(\".tsx\")) return false;\n // Check if it's a direct child of templates dir\n const relativePath = filePath.replace(absoluteTemplatesDir + \"/\", \"\");\n if (relativePath.includes(\"/\")) return false;\n return true;\n }\n\n // Helper to check if file is a code file (tsx/ts/js/jsx)\n function isCodeFile(filePath: string): boolean {\n return /\\.(tsx?|jsx?)$/.test(filePath);\n }\n\n // Helper to check if file is a CSS file in templates\n function isCssFile(filePath: string): boolean {\n return filePath.endsWith(\".css\");\n }\n\n // Suppress logging during initial scan\n let watcherReady = false;\n\n watcher.on(\"ready\", () => {\n watcherReady = true;\n });\n\n watcher.on(\"change\", async (filePath) => {\n if (!watcherReady) return;\n const fileName = filePath.split(\"/\").pop() || filePath;\n\n // Handle CSS file changes (styles.css or styles/*.css)\n if (isCssFile(filePath)) {\n console.log(chalk.blue(\" ↻\"), fileName, chalk.dim(\"changed\"));\n\n // Invalidate the virtual Tailwind CSS module to force recompilation\n const virtualMod = vite.moduleGraph.getModuleById(\"\\0virtual:pdfn-tailwind-css\");\n if (virtualMod) {\n vite.moduleGraph.invalidateModule(virtualMod);\n // Invalidate all modules that import the virtual module\n for (const importer of virtualMod.importers) {\n vite.moduleGraph.invalidateModule(importer);\n }\n }\n\n templates = await scanTemplates(absoluteTemplatesDir);\n broadcast({ type: \"reload\" });\n return;\n }\n\n // Log all code file changes (templates and components)\n if (isCodeFile(filePath)) {\n console.log(chalk.blue(\" ↻\"), fileName, chalk.dim(\"changed\"));\n\n // Invalidate the changed module and its dependencies in Vite's SSR cache\n const mod = vite.moduleGraph.getModuleById(filePath);\n if (mod) {\n vite.moduleGraph.invalidateModule(mod);\n }\n\n // Also invalidate the virtual Tailwind CSS module to force recompilation\n const virtualMod = vite.moduleGraph.getModuleById(\"\\0virtual:pdfn-tailwind-css\");\n if (virtualMod) {\n vite.moduleGraph.invalidateModule(virtualMod);\n // Invalidate all modules that import the virtual module\n for (const importer of virtualMod.importers) {\n vite.moduleGraph.invalidateModule(importer);\n }\n }\n }\n templates = await scanTemplates(absoluteTemplatesDir);\n broadcast({ type: \"reload\" });\n });\n\n watcher.on(\"add\", async (filePath) => {\n if (!watcherReady) return;\n const oldCount = templates.length;\n templates = await scanTemplates(absoluteTemplatesDir);\n // Only log if a new template was actually added (not components)\n if (templates.length > oldCount && isTemplateFile(filePath)) {\n const fileName = filePath.split(\"/\").pop() || filePath;\n console.log(chalk.green(\" +\"), fileName, chalk.dim(\"added\"));\n }\n // Send updated template list so sidebar can be refreshed\n broadcast({ type: \"templates\", templates: templates.map(t => ({ id: t.id, name: t.name, file: t.file })) });\n });\n\n watcher.on(\"unlink\", async (filePath) => {\n if (!watcherReady) return;\n const oldCount = templates.length;\n const fileName = filePath.split(\"/\").pop() || filePath;\n templates = await scanTemplates(absoluteTemplatesDir);\n // Only log if a template was actually removed (not components)\n if (templates.length < oldCount && isTemplateFile(filePath)) {\n console.log(chalk.red(\" -\"), fileName, chalk.dim(\"removed\"));\n }\n // Send updated template list so sidebar can be refreshed\n broadcast({ type: \"templates\", templates: templates.map(t => ({ id: t.id, name: t.name, file: t.file })) });\n });\n\n // Serve preview UI\n app.get(\"/\", (_req: Request, res: Response) => {\n const activeTemplate = templates[0]?.id ?? null;\n res.send(createPreviewHTML(templates, activeTemplate));\n });\n\n // API: Get template code\n app.get(\"/api/template/:id/code\", (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).send(\"Template not found\");\n return;\n }\n\n try {\n const code = readFileSync(template.path, \"utf-8\");\n res.type(\"text/plain\").send(code);\n } catch {\n res.status(500).send(\"Error reading template\");\n }\n });\n\n // Helper: Render a template to HTML using Vite\n // Templates use default parameter values for sample data (React Email pattern)\n async function renderTemplate(\n template: TemplateInfo,\n debugOptions: DebugOptions | false = false\n ): Promise<string> {\n const mod = await vite.ssrLoadModule(template.path);\n const Component = mod.default;\n const { render } = await vite.ssrLoadModule(\"@pdfn/react\");\n // Call with empty props - component's default parameter values provide sample data\n // Debug options are passed directly to render()\n return render(Component({}), { debug: debugOptions || undefined });\n }\n\n // Parse debug options from query params\n function parseDebugOptions(query: Record<string, unknown>): DebugOptions | false {\n const options: DebugOptions = {\n grid: query.grid === \"1\",\n margins: query.margins === \"1\",\n headers: query.headers === \"1\",\n breaks: query.breaks === \"1\",\n };\n\n // Return false if no options enabled\n const hasAny = Object.values(options).some((v) => v);\n return hasAny ? options : false;\n }\n\n // API: Get rendered HTML\n app.get(\"/api/template/:id/html\", async (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).send(\"Template not found\");\n return;\n }\n\n try {\n const start = performance.now();\n const debugOptions = parseDebugOptions(req.query as Record<string, unknown>);\n const html = await renderTemplate(template, debugOptions);\n const duration = Math.round(performance.now() - start);\n\n // Count pages from rendered HTML (look for pagedjs page markers)\n const pageMatches = html.match(/class=\"pagedjs_page\"/g);\n const pageCount = pageMatches ? pageMatches.length : 1;\n\n // Log render\n console.log(\n chalk.green(\" ✓\"),\n template.file,\n chalk.dim(\"→ HTML\"),\n chalk.cyan(`${duration}ms`)\n );\n\n res.setHeader(\"X-Render-Time\", duration.toString());\n res.setHeader(\"X-Page-Count\", pageCount.toString());\n // Note: Pagination time is measured client-side after Paged.js runs\n res.type(\"text/html\").send(html);\n } catch (error) {\n console.log(chalk.red(\" ✗\"), template.file, chalk.red(\"render failed\"));\n console.error(chalk.dim(\" \"), error);\n res.status(500).send(`Error rendering template: ${error}`);\n }\n });\n\n // Helper: Format bytes for display\n function formatBytes(bytes: number): string {\n if (bytes < 1024) return bytes + \"B\";\n if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + \"KB\";\n return (bytes / (1024 * 1024)).toFixed(2) + \"MB\";\n }\n\n // API: Generate PDF\n app.get(\"/api/template/:id/pdf\", async (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).send(\"Template not found\");\n return;\n }\n\n try {\n const debugOptions = parseDebugOptions(req.query as Record<string, unknown>);\n const html = await renderTemplate(template, debugOptions);\n const result = await browserManager.withPage(async (page) => {\n return generatePdf(page, html, { timeout: 30000 });\n });\n\n // Log PDF generation - first line: request summary\n const { metrics, warnings, assets } = result;\n console.log(\n chalk.green(\" ✓\"),\n template.file,\n chalk.dim(\"→ PDF •\"),\n chalk.cyan(`${metrics.total}ms`),\n chalk.dim(\"•\"),\n formatBytes(metrics.pdfSize)\n );\n\n // Second line: details (pages, assets, timing) - all separated by •\n const pageStr = `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`;\n const images = assets.filter((a) => a.type === \"image\");\n const fonts = assets.filter((a) => a.type === \"font\");\n const assetParts: string[] = [];\n if (images.length > 0) assetParts.push(`${images.length} image${images.length > 1 ? \"s\" : \"\"}`);\n if (fonts.length > 0) assetParts.push(`${fonts.length} font${fonts.length > 1 ? \"s\" : \"\"}`);\n const assetStr = assetParts.length > 0 ? assetParts.join(\" • \") + \" • \" : \"\";\n const timingStr = `load ${metrics.contentLoad}ms • paginate ${metrics.pagedJs}ms • capture ${metrics.pdfCapture}ms`;\n console.log(chalk.dim(` ${pageStr} • ${assetStr}${timingStr}`));\n\n // Log warnings\n if (warnings.length > 0) {\n warnings.forEach((w) => {\n console.log(chalk.yellow(\" ⚠\"), chalk.yellow(w));\n });\n }\n\n // Add metrics headers\n res.setHeader(\"X-PDF-Total-Time\", metrics.total.toString());\n res.setHeader(\"X-PDF-Pages\", metrics.pageCount.toString());\n res.setHeader(\"X-PDF-Size\", metrics.pdfSize.toString());\n res.setHeader(\"X-PDF-Capture-Time\", metrics.pdfCapture.toString());\n res.setHeader(\"X-PDF-Assets\", result.assets.length.toString());\n res.setHeader(\"X-PDF-Warnings\", warnings.length.toString());\n\n res.setHeader(\"Content-Type\", \"application/pdf\");\n res.setHeader(\"Content-Disposition\", `inline; filename=\"${template.id}.pdf\"`);\n res.send(result.buffer);\n } catch (error) {\n console.log(chalk.red(\" ✗\"), template.file, chalk.red(\"PDF generation failed\"));\n console.error(chalk.dim(\" \"), error);\n res.status(500).send(`Error generating PDF: ${error}`);\n }\n });\n\n // API: Generate PDF and return metrics (JSON)\n app.get(\"/api/template/:id/pdf-metrics\", async (req: Request, res: Response) => {\n const template = templates.find((t) => t.id === req.params.id);\n if (!template) {\n res.status(404).json({ error: \"Template not found\" });\n return;\n }\n\n try {\n const debugOptions = parseDebugOptions(req.query as Record<string, unknown>);\n const html = await renderTemplate(template, debugOptions);\n const result = await browserManager.withPage(async (page) => {\n return generatePdf(page, html, { timeout: 30000 });\n });\n\n // Log PDF metrics - first line: request summary\n const { metrics, warnings, assets } = result;\n console.log(\n chalk.green(\" ✓\"),\n template.file,\n chalk.dim(\"→ PDF metrics •\"),\n chalk.cyan(`${metrics.total}ms`),\n chalk.dim(\"•\"),\n formatBytes(metrics.pdfSize)\n );\n\n // Second line: details (pages, assets, timing) - all separated by •\n {\n const pageStr = `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`;\n const images = assets.filter((a) => a.type === \"image\");\n const fonts = assets.filter((a) => a.type === \"font\");\n const assetParts: string[] = [];\n if (images.length > 0) assetParts.push(`${images.length} image${images.length > 1 ? \"s\" : \"\"}`);\n if (fonts.length > 0) assetParts.push(`${fonts.length} font${fonts.length > 1 ? \"s\" : \"\"}`);\n const assetStr = assetParts.length > 0 ? assetParts.join(\" • \") + \" • \" : \"\";\n const timingStr = `load ${metrics.contentLoad}ms • paginate ${metrics.pagedJs}ms • capture ${metrics.pdfCapture}ms`;\n console.log(chalk.dim(` ${pageStr} • ${assetStr}${timingStr}`));\n }\n\n if (warnings.length > 0) {\n warnings.forEach((w) => {\n console.log(chalk.yellow(\" ⚠\"), chalk.yellow(w));\n });\n }\n\n res.json({\n metrics: result.metrics,\n assets: result.assets,\n warnings: result.warnings,\n });\n } catch (error) {\n console.log(chalk.red(\" ✗\"), template.file, chalk.red(\"PDF metrics failed\"));\n console.error(chalk.dim(\" \"), error);\n res.status(500).json({ error: `Error generating PDF: ${error}` });\n }\n });\n\n // Start server\n await new Promise<void>((resolve, reject) => {\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n console.error(chalk.red(`\\n ✗ Port ${port} is already in use.\\n`));\n console.error(chalk.dim(` Either stop the existing server or use a different port:`));\n console.error(chalk.dim(` npx pdfn dev --port ${port + 1}\\n`));\n process.exit(1);\n }\n reject(err);\n });\n server.listen(port, () => resolve());\n });\n\n // Pre-launch Chromium for PDF generation\n await browserManager.getBrowser();\n\n // Graceful shutdown\n const shutdown = async () => {\n console.log(chalk.dim(\"\\n Shutting down...\"));\n watcher.close();\n await vite.close();\n await browserManager.close();\n server.close();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n\n // Open Chromium (same browser used for PDF generation = true WYSIWYG)\n function openChromium() {\n const chromiumPath = puppeteer.executablePath();\n console.log(chalk.dim(\" Opening in Chromium...\\n\"));\n spawn(chromiumPath, [`http://localhost:${port}`], {\n detached: true,\n stdio: \"ignore\",\n }).unref();\n }\n\n console.log(chalk.dim(` Templates: ${displayPath} (${templateCount})`));\n console.log(chalk.green(`\\n ✓ Ready at ${chalk.cyan(`http://localhost:${port}`)}\\n`));\n\n if (!open) {\n console.log(chalk.dim(` Tip: PDFs are generated with Chromium. For accurate preview,`));\n console.log(chalk.dim(` open in Chrome or Chromium-based browsers.\\n`));\n }\n\n console.log(chalk.dim(` Shortcuts`));\n console.log(chalk.dim(` › ${chalk.white(\"o\")} open in Chromium`));\n console.log(chalk.dim(` › ${chalk.white(\"q\")} quit\\n`));\n\n if (open) {\n openChromium();\n }\n\n // Keyboard shortcuts\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (key: string) => {\n if (key === \"o\" || key === \"O\") {\n openChromium();\n } else if (key === \"q\" || key === \"Q\" || key === \"\\u0003\") {\n // q or Ctrl+C\n shutdown();\n }\n });\n }\n}\n\nexport const devCommand = new Command(\"dev\")\n .description(\"Start development server with live preview\")\n .option(\"--port <number>\", \"Server port (env: PDFN_PORT)\", process.env.PDFN_PORT ?? \"3456\")\n .option(\"--open\", \"Open browser automatically\")\n .option(\"--mode <mode>\", \"Environment mode (loads .env.[mode])\", \"development\")\n .action(async (options) => {\n // Load environment variables based on mode (Vite pattern)\n loadEnv(options.mode);\n\n const port = parseInt(options.port, 10);\n\n await startDevServer({\n port,\n open: options.open ?? false,\n mode: options.mode,\n });\n });\n","import express from \"express\";\nimport type { Express, Request, Response, NextFunction } from \"express\";\nimport { BrowserManager } from \"./browser\";\nimport { createGenerateHandler } from \"./routes\";\nimport { type PdfResult } from \"./pdf\";\n\nexport interface BaseServerOptions {\n /** Max concurrent pages (default: env.PDFN_MAX_CONCURRENT || 5) */\n maxConcurrent?: number;\n /** Request timeout in ms (default: env.PDFN_TIMEOUT || 30000) */\n timeout?: number;\n /** Enable request logging (default: true) */\n enableLogging?: boolean;\n /** Custom logger for requests */\n onRequest?: (method: string, path: string, status: number, duration: number, extra?: string) => void;\n /** Custom logger for PDF details */\n onPdfResult?: (result: PdfResult) => void;\n /** Callback on successful PDF generation */\n onSuccess?: (result: PdfResult) => void;\n /** Custom logger for errors */\n onError?: (message: string) => void;\n}\n\nexport interface BaseServer {\n app: Express;\n browserManager: BrowserManager;\n maxConcurrent: number;\n timeout: number;\n}\n\n/**\n * Create a base PDFN server with common middleware and routes.\n *\n * This is shared between `dev` and `serve` commands.\n * Returns the Express app and BrowserManager for further customization.\n *\n * Includes:\n * - JSON body parsing (50mb limit)\n * - Request logging middleware (optional)\n * - POST /generate endpoint\n * - GET /health endpoint\n */\nexport function createBaseServer(options: BaseServerOptions = {}): BaseServer {\n const maxConcurrent =\n options.maxConcurrent ??\n parseInt(process.env.PDFN_MAX_CONCURRENT ?? \"5\", 10);\n const timeout =\n options.timeout ?? parseInt(process.env.PDFN_TIMEOUT ?? \"30000\", 10);\n const enableLogging = options.enableLogging ?? true;\n\n const app = express();\n const browserManager = new BrowserManager({ maxConcurrent, timeout });\n\n // JSON body parsing\n app.use(express.json({ limit: \"50mb\" }));\n\n // Request logging middleware\n if (enableLogging && options.onRequest) {\n const onRequest = options.onRequest;\n const onPdfResult = options.onPdfResult;\n\n app.use((req: Request, res: Response, next: NextFunction) => {\n // Skip noisy requests\n const skipPaths = [\"/favicon.ico\", \"/robots.txt\"];\n if (skipPaths.includes(req.path)) {\n next();\n return;\n }\n\n const start = performance.now();\n\n res.on(\"finish\", () => {\n const duration = performance.now() - start;\n\n // For /generate, include page count and size\n let extra: string | undefined;\n if (req.path === \"/generate\" && res.statusCode === 200) {\n const pages = res.getHeader(\"X-PDFN-Page-Count\");\n const size = Number(res.getHeader(\"X-PDFN-PDF-Size\")) || 0;\n const sizeKB = (size / 1024).toFixed(1);\n extra = `${pages} pages • ${sizeKB}KB`;\n }\n\n onRequest(req.method, req.path, res.statusCode, duration, extra);\n\n // Log PDF details if available\n const pdfResult = (res as any)._pdfResult as PdfResult | undefined;\n if (pdfResult && onPdfResult) {\n onPdfResult(pdfResult);\n }\n });\n\n next();\n });\n }\n\n // Health check endpoint\n app.get(\"/health\", (_req: Request, res: Response) => {\n res.json({\n status: \"ok\",\n browser: browserManager.isConnected() ? \"connected\" : \"disconnected\",\n activePages: browserManager.getActivePages(),\n maxConcurrent: browserManager.getMaxConcurrent(),\n });\n });\n\n // PDF generation endpoint\n app.post(\n \"/generate\",\n createGenerateHandler(browserManager, {\n timeout,\n onSuccess: options.onSuccess,\n onError: options.onError,\n })\n );\n\n return {\n app,\n browserManager,\n maxConcurrent,\n timeout,\n };\n}\n","import puppeteer, { Browser, Page } from \"puppeteer\";\n\nexport interface BrowserManagerOptions {\n /** Max concurrent pages (default: env.PDFN_MAX_CONCURRENT || 5) */\n maxConcurrent?: number;\n /** Request timeout in ms (default: env.PDFN_TIMEOUT || 30000) */\n timeout?: number;\n}\n\n/**\n * Manages a single Puppeteer browser instance with multiple concurrent pages\n *\n * Architecture: Single browser + multiple pages (industry standard pattern)\n * - Lower memory footprint (~150MB browser + ~30MB/page)\n * - Fast page creation (~50ms vs ~1-2s for new browser)\n * - Auto-restart on browser crash/disconnect\n */\nexport class BrowserManager {\n private browser: Browser | null = null;\n private launching: Promise<Browser> | null = null;\n private activePages = 0;\n private maxConcurrent: number;\n private timeout: number;\n\n constructor(options: BrowserManagerOptions = {}) {\n this.maxConcurrent =\n options.maxConcurrent ??\n parseInt(process.env.PDFN_MAX_CONCURRENT ?? \"5\", 10);\n this.timeout =\n options.timeout ?? parseInt(process.env.PDFN_TIMEOUT ?? \"30000\", 10);\n }\n\n /**\n * Get or create the browser instance\n */\n async getBrowser(): Promise<Browser> {\n if (this.browser?.connected) {\n return this.browser;\n }\n\n // If already launching, wait for that\n if (this.launching) {\n return this.launching;\n }\n\n // Launch new browser\n this.launching = puppeteer.launch({\n headless: true,\n args: [\n \"--no-sandbox\",\n \"--disable-setuid-sandbox\",\n \"--disable-dev-shm-usage\",\n \"--disable-gpu\",\n \"--disable-extensions\",\n \"--mute-audio\",\n \"--disable-notifications\",\n ],\n });\n\n try {\n this.browser = await this.launching;\n this.setupBrowserListeners(this.browser);\n return this.browser;\n } finally {\n this.launching = null;\n }\n }\n\n /**\n * Setup browser event listeners for auto-restart on crash\n */\n private setupBrowserListeners(browser: Browser): void {\n browser.on(\"disconnected\", () => {\n this.browser = null;\n // activePages will naturally drain as withPage catches errors\n });\n }\n\n /**\n * Create a new page for PDF generation\n */\n async createPage(): Promise<Page> {\n const browser = await this.getBrowser();\n const page = await browser.newPage();\n page.setDefaultTimeout(this.timeout);\n return page;\n }\n\n /**\n * Execute a function with a managed page\n *\n * This pattern ensures:\n * - Concurrency limits are respected\n * - Pages are always closed after use\n * - Active page count is accurate\n *\n * @throws Error if max concurrent pages reached\n */\n async withPage<T>(fn: (page: Page) => Promise<T>): Promise<T> {\n if (this.activePages >= this.maxConcurrent) {\n throw new Error(\"Server busy - max concurrent requests reached\");\n }\n\n this.activePages++;\n let page: Page | null = null;\n\n try {\n page = await this.createPage();\n return await fn(page);\n } finally {\n this.activePages--;\n if (page) {\n await page.close().catch(() => {\n // Ignore close errors (browser may have disconnected)\n });\n }\n }\n }\n\n /**\n * Check if browser is connected\n */\n isConnected(): boolean {\n return this.browser?.connected ?? false;\n }\n\n /**\n * Get current number of active pages\n */\n getActivePages(): number {\n return this.activePages;\n }\n\n /**\n * Get max concurrent pages limit\n */\n getMaxConcurrent(): number {\n return this.maxConcurrent;\n }\n\n /**\n * Get configured timeout\n */\n getTimeout(): number {\n return this.timeout;\n }\n\n /**\n * Close the browser and clean up\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close();\n this.browser = null;\n }\n }\n}\n","/**\n * Simple debug logging utility\n *\n * Enable with DEBUG=pdfn:cli or DEBUG=pdfn:* or DEBUG=pdfn\n *\n * This is a lightweight alternative to the `debug` npm package.\n * Supports namespace filtering similar to the debug package convention.\n */\n\n// Debug logging - enable with DEBUG=pdfn:cli or DEBUG=pdfn:* or DEBUG=pdfn\nconst debugEnv = process.env.DEBUG ?? \"\";\nconst isEnabled =\n debugEnv.includes(\"pdfn:cli\") ||\n debugEnv.includes(\"pdfn:*\") ||\n debugEnv === \"pdfn\" ||\n debugEnv.includes(\"pdfn,\") ||\n debugEnv.endsWith(\",pdfn\");\n\n/**\n * Debug logger - only logs when DEBUG=pdfn:cli (or pdfn:* or pdfn) is set\n */\nexport const debug = isEnabled\n ? (message: string, ...args: unknown[]) => {\n console.log(`[pdfn:cli] ${message}`, ...args);\n }\n : () => {};\n\n/**\n * Check if debug logging is enabled\n */\nexport const isDebugEnabled = () => isEnabled;\n","import type { Page, PDFOptions, HTTPRequest, HTTPResponse } from \"puppeteer\";\nimport { debug } from \"../utils/debug\";\n\nexport interface PdfGenerationOptions {\n /** PDF format (default: A4) */\n format?: \"A4\" | \"Letter\" | \"Legal\" | \"Tabloid\" | \"A3\" | \"A5\";\n /** Print background graphics */\n printBackground?: boolean;\n /** Timeout for waiting for ready state (ms) */\n timeout?: number;\n}\n\n/** Asset information tracked during PDF generation */\nexport interface AssetInfo {\n /** Asset URL */\n url: string;\n /** Asset type (image, font, stylesheet, script, other) */\n type: \"image\" | \"font\" | \"stylesheet\" | \"script\" | \"other\";\n /** Size in bytes (0 if failed) */\n size: number;\n /** Load time in ms */\n duration: number;\n /** Whether the asset loaded successfully */\n success: boolean;\n /** Error message if failed */\n error?: string;\n}\n\nexport interface PdfResult {\n /** PDF buffer */\n buffer: Buffer;\n /** Generation metrics */\n metrics: {\n /** Total generation time in ms */\n total: number;\n /** Time waiting for content to load */\n contentLoad: number;\n /** Time waiting for Paged.js */\n pagedJs: number;\n /** Time for PDF capture */\n pdfCapture: number;\n /** Number of pages */\n pageCount: number;\n /** PDF file size in bytes */\n pdfSize: number;\n };\n /** Assets loaded during generation */\n assets: AssetInfo[];\n /** Warnings detected during generation */\n warnings: string[];\n}\n\n/** Size threshold for large asset warning (200KB - web best practice) */\nconst LARGE_ASSET_THRESHOLD = 200 * 1024;\n\n/** Duration threshold for slow asset warning (1000ms - lenient for fonts) */\nconst SLOW_ASSET_THRESHOLD = 1000;\n\n/** Determine asset type from resource type */\nfunction getAssetType(resourceType: string): AssetInfo[\"type\"] {\n switch (resourceType) {\n case \"image\":\n return \"image\";\n case \"font\":\n return \"font\";\n case \"stylesheet\":\n return \"stylesheet\";\n case \"script\":\n return \"script\";\n default:\n return \"other\";\n }\n}\n\n/** Get short URL for display (remove data: prefix, truncate long URLs) */\nfunction getShortUrl(url: string): string {\n if (url.startsWith(\"data:\")) {\n const match = url.match(/^data:([^;,]+)/);\n return match ? `data:${match[1]}...` : \"data:...\";\n }\n if (url.length > 80) {\n return url.substring(0, 77) + \"...\";\n }\n return url;\n}\n\n/**\n * Generate PDF from HTML content using a Puppeteer page\n */\nexport async function generatePdf(\n page: Page,\n html: string,\n options: PdfGenerationOptions = {}\n): Promise<PdfResult> {\n const {\n format = \"A4\",\n printBackground = true,\n timeout = 30000,\n } = options;\n\n const startTime = performance.now();\n let contentLoadTime = 0;\n let pagedJsTime = 0;\n let pdfCaptureTime = 0;\n let pageCount = 0;\n\n // Asset tracking\n const assets: AssetInfo[] = [];\n const requestStartTimes = new Map<string, number>();\n const warnings: string[] = [];\n\n // Request handler to track start times\n const onRequest = (request: HTTPRequest) => {\n const url = request.url();\n const resourceType = request.resourceType();\n\n // Only track relevant resource types\n if ([\"image\", \"font\", \"stylesheet\", \"script\"].includes(resourceType)) {\n requestStartTimes.set(url, performance.now());\n }\n };\n\n // Response handler to track completed requests\n const onResponse = (response: HTTPResponse) => {\n const url = response.url();\n const request = response.request();\n const resourceType = request.resourceType();\n const startTime = requestStartTimes.get(url);\n\n if (startTime === undefined) return;\n\n const duration = Math.round(performance.now() - startTime);\n const status = response.status();\n const success = status >= 200 && status < 400;\n\n // Get content length from headers\n const contentLength = response.headers()[\"content-length\"];\n const size = contentLength ? parseInt(contentLength, 10) : 0;\n\n const asset: AssetInfo = {\n url: getShortUrl(url),\n type: getAssetType(resourceType),\n size,\n duration,\n success,\n };\n\n if (!success) {\n asset.error = `HTTP ${status}`;\n warnings.push(`Failed: ${asset.url} (${status})`);\n } else {\n if (size > LARGE_ASSET_THRESHOLD) {\n warnings.push(`Large: ${asset.url} (${(size / 1024).toFixed(0)}KB)`);\n }\n if (duration > SLOW_ASSET_THRESHOLD) {\n warnings.push(`Slow: ${asset.url} (${duration}ms)`);\n }\n }\n\n assets.push(asset);\n requestStartTimes.delete(url);\n };\n\n // Request failed handler\n const onRequestFailed = (request: HTTPRequest) => {\n const url = request.url();\n const resourceType = request.resourceType();\n const startTime = requestStartTimes.get(url);\n\n if (startTime === undefined) return;\n\n const duration = Math.round(performance.now() - startTime);\n const failure = request.failure();\n const errorText = failure?.errorText || \"Unknown error\";\n\n const asset: AssetInfo = {\n url: getShortUrl(url),\n type: getAssetType(resourceType),\n size: 0,\n duration,\n success: false,\n error: errorText,\n };\n\n warnings.push(`Failed: ${asset.url} (${errorText})`);\n assets.push(asset);\n requestStartTimes.delete(url);\n };\n\n // Set up request interception\n page.on(\"request\", onRequest);\n page.on(\"response\", onResponse);\n page.on(\"requestfailed\", onRequestFailed);\n\n try {\n // Set content and wait for network idle\n const contentStart = performance.now();\n await page.setContent(html, {\n waitUntil: \"networkidle0\",\n timeout,\n });\n contentLoadTime = performance.now() - contentStart;\n\n // Wait for PDFN.ready to be true (Paged.js completion)\n const pagedStart = performance.now();\n await page.waitForFunction(\n () => (window as any).PDFN?.ready === true,\n { timeout }\n );\n pagedJsTime = performance.now() - pagedStart;\n\n // Get page count from PDFN metrics\n pageCount = await page.evaluate(() => {\n return (window as any).PDFN?.metrics?.pages ?? 1;\n });\n\n // Generate PDF\n const pdfStart = performance.now();\n const pdfOptions: PDFOptions = {\n format,\n printBackground,\n preferCSSPageSize: true,\n tagged: true, // Accessibility: generates tagged PDF for screen readers\n outline: true, // Accessibility: auto-generates bookmarks from headings\n };\n\n const buffer = await page.pdf(pdfOptions);\n pdfCaptureTime = performance.now() - pdfStart;\n\n const totalTime = performance.now() - startTime;\n const pdfBuffer = Buffer.from(buffer);\n\n debug(\n `pdf: ${Math.round(totalTime)}ms (load: ${Math.round(contentLoadTime)}ms, paged: ${Math.round(pagedJsTime)}ms, capture: ${Math.round(pdfCaptureTime)}ms) - ${pageCount} pages, ${(pdfBuffer.length / 1024).toFixed(1)}KB`\n );\n\n if (assets.length > 0) {\n debug(`assets: ${assets.length} (${assets.filter(a => !a.success).length} failed)`);\n }\n\n if (warnings.length > 0) {\n warnings.forEach(w => debug(`warning: ${w}`));\n }\n\n return {\n buffer: pdfBuffer,\n metrics: {\n total: Math.round(totalTime),\n contentLoad: Math.round(contentLoadTime),\n pagedJs: Math.round(pagedJsTime),\n pdfCapture: Math.round(pdfCaptureTime),\n pageCount,\n pdfSize: pdfBuffer.length,\n },\n assets,\n warnings,\n };\n } finally {\n // Clean up event listeners\n page.off(\"request\", onRequest);\n page.off(\"response\", onResponse);\n page.off(\"requestfailed\", onRequestFailed);\n\n // Close the page after use\n await page.close().catch(() => {});\n }\n}\n","import type { Request, Response } from \"express\";\nimport type { BrowserManager } from \"./browser\";\nimport { generatePdf, type PdfResult } from \"./pdf\";\n\ninterface GenerateRequestBody {\n html?: string;\n options?: {\n timeout?: number;\n printBackground?: boolean;\n preferCSSPageSize?: boolean;\n };\n}\n\ninterface GenerateHandlerOptions {\n /** Default timeout in ms (default: 30000) */\n timeout?: number;\n /** Optional logger for PDF generation results */\n onSuccess?: (result: PdfResult) => void;\n /** Optional logger for errors */\n onError?: (error: string) => void;\n}\n\n/**\n * Create a /generate POST handler for PDF generation\n *\n * This is shared between `dev` and `serve` commands to avoid duplication.\n * Each server provides its own BrowserManager instance.\n *\n * @example\n * ```ts\n * const browserManager = new BrowserManager({ maxConcurrent: 5 });\n * app.post(\"/generate\", createGenerateHandler(browserManager));\n * ```\n */\nexport function createGenerateHandler(\n browserManager: BrowserManager,\n options: GenerateHandlerOptions = {}\n) {\n const { timeout = 30000, onSuccess, onError } = options;\n\n return async (req: Request, res: Response) => {\n const { html, options: pdfOptions } = req.body as GenerateRequestBody;\n const format = req.query.format as string | undefined;\n\n if (!html) {\n res.status(400).json({ error: \"HTML content is required\" });\n return;\n }\n\n // Return HTML directly if format=html (for debugging)\n if (format === \"html\") {\n res.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n res.send(html);\n return;\n }\n\n try {\n const result = await browserManager.withPage(async (page) => {\n return generatePdf(page, html, {\n ...pdfOptions,\n timeout: pdfOptions?.timeout ?? timeout,\n });\n });\n\n // Set response headers with metrics\n res.setHeader(\"Content-Type\", \"application/pdf\");\n res.setHeader(\"X-PDFN-Total-Time\", result.metrics.total.toString());\n res.setHeader(\"X-PDFN-Content-Load\", result.metrics.contentLoad.toString());\n res.setHeader(\"X-PDFN-PagedJs-Time\", result.metrics.pagedJs.toString());\n res.setHeader(\"X-PDFN-PDF-Capture\", result.metrics.pdfCapture.toString());\n res.setHeader(\"X-PDFN-Page-Count\", result.metrics.pageCount.toString());\n res.setHeader(\"X-PDFN-PDF-Size\", result.metrics.pdfSize.toString());\n\n // Attach result for logging middleware (used by serve command)\n (res as any)._pdfResult = result;\n\n // Call success callback if provided\n onSuccess?.(result);\n\n res.send(result.buffer);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n\n // Call error callback if provided\n onError?.(message);\n\n if (message.includes(\"Server busy\")) {\n res.status(503).json({ error: message });\n return;\n }\n\n res.status(500).json({ error: message });\n }\n };\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { config } from \"dotenv\";\n\n/**\n * Load environment variables following Vite's pattern.\n * Priority (later overrides earlier):\n * .env → .env.local → .env.[mode] → .env.[mode].local\n *\n * @param mode - Environment mode (e.g., \"development\", \"production\")\n */\nexport function loadEnv(mode: string): void {\n const cwd = process.cwd();\n\n // Files in order of priority (first loaded = lowest priority)\n const envFiles = [\n \".env\",\n \".env.local\",\n `.env.${mode}`,\n `.env.${mode}.local`,\n ];\n\n for (const file of envFiles) {\n const filePath = resolve(cwd, file);\n if (existsSync(filePath)) {\n // quiet: true suppresses dotenv's verbose output in v17+\n config({ path: filePath, override: true, quiet: true });\n }\n }\n}\n","import { Command } from \"commander\";\nimport { createServer } from \"../server/index\";\nimport { logger } from \"../utils/logger\";\nimport { loadEnv } from \"../utils/env\";\n\nexport const serveCommand = new Command(\"serve\")\n .description(\"Start production server (headless, no UI)\")\n .option(\"--port <number>\", \"Server port (env: PDFN_PORT)\", \"3456\")\n .option(\"--max-concurrent <number>\", \"Max concurrent pages (env: PDFN_MAX_CONCURRENT)\", \"5\")\n .option(\"--timeout <ms>\", \"Request timeout in ms (env: PDFN_TIMEOUT)\", \"30000\")\n .option(\"--mode <mode>\", \"Environment mode (loads .env.[mode])\", \"production\")\n .action(async (options) => {\n // Load environment variables based on mode (Vite pattern)\n loadEnv(options.mode);\n\n const port = parseInt(options.port, 10);\n const maxConcurrent = parseInt(options.maxConcurrent, 10);\n const timeout = parseInt(options.timeout, 10);\n\n const server = createServer({ port, maxConcurrent, timeout });\n\n // Handle graceful shutdown\n const shutdown = async () => {\n logger.shutdown();\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n\n await server.start();\n });\n","import type { PdfResult } from \"../server/pdf\";\n\n/**\n * Simple logger with colors and formatting for CLI output\n */\n\n// ANSI color codes\nconst colors = {\n reset: \"\\x1b[0m\",\n dim: \"\\x1b[2m\",\n bold: \"\\x1b[1m\",\n\n // Foreground\n black: \"\\x1b[30m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n gray: \"\\x1b[90m\",\n\n // Background\n bgGreen: \"\\x1b[42m\",\n bgYellow: \"\\x1b[43m\",\n bgRed: \"\\x1b[41m\",\n bgCyan: \"\\x1b[46m\",\n} as const;\n\n// Color helper functions\nconst c = {\n dim: (s: string) => `${colors.dim}${s}${colors.reset}`,\n bold: (s: string) => `${colors.bold}${s}${colors.reset}`,\n green: (s: string) => `${colors.green}${s}${colors.reset}`,\n red: (s: string) => `${colors.red}${s}${colors.reset}`,\n yellow: (s: string) => `${colors.yellow}${s}${colors.reset}`,\n blue: (s: string) => `${colors.blue}${s}${colors.reset}`,\n cyan: (s: string) => `${colors.cyan}${s}${colors.reset}`,\n gray: (s: string) => `${colors.gray}${s}${colors.reset}`,\n magenta: (s: string) => `${colors.magenta}${s}${colors.reset}`,\n};\n\nfunction timestamp(): string {\n return c.dim(new Date().toLocaleTimeString(\"en-US\", { hour12: false }));\n}\n\nfunction formatMs(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`;\n return `${(ms / 1000).toFixed(2)}s`;\n}\n\nexport const logger = {\n /**\n * Log info message\n */\n info: (message: string, ...args: unknown[]) => {\n console.log(`${timestamp()} ${c.cyan(\"ℹ\")} ${message}`, ...args);\n },\n\n /**\n * Log success message\n */\n success: (message: string, ...args: unknown[]) => {\n console.log(`${timestamp()} ${c.green(\"✓\")} ${message}`, ...args);\n },\n\n /**\n * Log warning message\n */\n warn: (message: string, ...args: unknown[]) => {\n console.log(`${timestamp()} ${c.yellow(\"⚠\")} ${c.yellow(message)}`, ...args);\n },\n\n /**\n * Log error message\n */\n error: (message: string, ...args: unknown[]) => {\n console.error(`${timestamp()} ${c.red(\"✗\")} ${c.red(message)}`, ...args);\n },\n\n /**\n * Log HTTP request\n */\n request: (\n method: string,\n path: string,\n status: number,\n duration: number,\n extra?: string\n ) => {\n const methodColor =\n method === \"GET\" ? c.green : method === \"POST\" ? c.cyan : c.yellow;\n const statusColor =\n status >= 500\n ? c.red\n : status >= 400\n ? c.yellow\n : status >= 300\n ? c.blue\n : c.green;\n\n const line = [\n timestamp(),\n methodColor(method.padEnd(4)),\n path,\n statusColor(status.toString()),\n c.dim(formatMs(duration)),\n extra ? c.dim(extra) : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n console.log(line);\n },\n\n /**\n * Log server startup banner\n */\n banner: (port: number, maxConcurrent: number, timeout: number) => {\n console.log();\n console.log(` ${c.bold(\"pdfn serve\")}`);\n console.log();\n console.log(` ${c.green(\"✓\")} Ready at ${c.cyan(`http://localhost:${port}`)}`);\n console.log(` ${c.dim(`${maxConcurrent} concurrent | ${formatMs(timeout)} timeout`)}`);\n console.log();\n console.log(` ${c.dim(\"Endpoints:\")}`);\n console.log(` ${c.green(\"POST\")} /generate ${c.dim(\"HTML → PDF\")}`);\n console.log(` ${c.blue(\"GET\")} /health ${c.dim(\"Health check\")}`);\n console.log();\n },\n\n /**\n * Log PDF details (pages, assets, timing) on a single line\n * Used after the request line has been logged\n */\n pdfDetails: (result: PdfResult) => {\n const { metrics, assets, warnings } = result;\n\n // Build details line: pages • assets • timing (all separated by •)\n const pageStr = `${metrics.pageCount} page${metrics.pageCount > 1 ? \"s\" : \"\"}`;\n\n const images = assets.filter((a) => a.type === \"image\");\n const fonts = assets.filter((a) => a.type === \"font\");\n const assetParts: string[] = [];\n if (images.length > 0) assetParts.push(`${images.length} image${images.length > 1 ? \"s\" : \"\"}`);\n if (fonts.length > 0) assetParts.push(`${fonts.length} font${fonts.length > 1 ? \"s\" : \"\"}`);\n const assetStr = assetParts.length > 0 ? assetParts.join(\" • \") + \" • \" : \"\";\n\n const timingStr = `load ${metrics.contentLoad}ms • paginate ${metrics.pagedJs}ms • capture ${metrics.pdfCapture}ms`;\n\n console.log(c.dim(` ${pageStr} • ${assetStr}${timingStr}`));\n\n // Warnings\n for (const w of warnings) {\n console.log(` ${c.yellow(\"⚠\")} ${c.yellow(w)}`);\n }\n },\n\n /**\n * Log PDF generation metrics (simple format for inline use)\n */\n pdf: (metrics: {\n total: number;\n contentLoad: number;\n pagedJs: number;\n pdfCapture: number;\n pageCount: number;\n }) => {\n const parts = [\n `${metrics.pageCount} ${metrics.pageCount === 1 ? \"page\" : \"pages\"}`,\n formatMs(metrics.total),\n c.dim(\n `(load: ${formatMs(metrics.contentLoad)}, paged: ${formatMs(metrics.pagedJs)}, pdf: ${formatMs(metrics.pdfCapture)})`\n ),\n ];\n return parts.join(\" \");\n },\n\n /**\n * Log browser status\n */\n browser: (status: \"launching\" | \"ready\" | \"disconnected\" | \"closed\") => {\n switch (status) {\n case \"launching\":\n logger.info(\"Initializing...\");\n break;\n case \"ready\":\n logger.success(\"Ready\");\n break;\n case \"disconnected\":\n logger.warn(\"PDF engine disconnected, will restart on next request\");\n break;\n case \"closed\":\n logger.info(\"Shutting down...\");\n break;\n }\n },\n\n /**\n * Log shutdown\n */\n shutdown: () => {\n console.log();\n logger.info(\"Shutting down...\");\n },\n\n // Raw color helpers for custom formatting\n c,\n};\n","import type { Express, Request, Response } from \"express\";\nimport { createBaseServer } from \"./base\";\nimport { logger } from \"../utils/logger\";\n\nexport interface ServerOptions {\n /** Server port (default: env.PDFN_PORT || 3456) */\n port?: number;\n /** Max concurrent pages (default: env.PDFN_MAX_CONCURRENT || 5) */\n maxConcurrent?: number;\n /** Request timeout in ms (default: env.PDFN_TIMEOUT || 30000) */\n timeout?: number;\n}\n\nexport interface PDFNServer {\n app: Express;\n start: () => Promise<void>;\n stop: () => Promise<void>;\n}\n\n/**\n * Create a PDFN server instance\n *\n * Configuration priority: options > environment variables > defaults\n *\n * Environment variables:\n * - PDFN_PORT: Server port (default: 3456)\n * - PDFN_MAX_CONCURRENT: Max concurrent pages (default: 5)\n * - PDFN_TIMEOUT: Request timeout in ms (default: 30000)\n *\n * @example\n * ```ts\n * import { createServer } from 'pdfn/server';\n *\n * const server = createServer({ port: 3456, maxConcurrent: 10 });\n * await server.start();\n * ```\n */\nexport function createServer(options: ServerOptions = {}): PDFNServer {\n const port =\n options.port ?? parseInt(process.env.PDFN_PORT ?? \"3456\", 10);\n\n // Create base server with shared middleware and routes\n const { app, browserManager, maxConcurrent, timeout } = createBaseServer({\n maxConcurrent: options.maxConcurrent,\n timeout: options.timeout,\n enableLogging: true,\n onRequest: (method, path, status, duration, extra) => {\n logger.request(method, path, status, duration, extra);\n },\n onPdfResult: (result) => {\n logger.pdfDetails(result);\n },\n onError: (message) => {\n if (message.includes(\"Server busy\")) {\n logger.warn(`Rate limited: ${browserManager.getActivePages()}/${maxConcurrent} pages in use`);\n } else {\n logger.error(`PDF generation failed: ${message}`);\n }\n },\n });\n\n let server: ReturnType<typeof app.listen> | null = null;\n\n // Landing page - helpful message for browser visitors\n app.get(\"/\", (_req: Request, res: Response) => {\n res.type(\"text/plain\").send(`PDFN Server\n\nThis is a headless API server for PDF generation.\n\nEndpoints:\n POST /generate Generate PDF from HTML\n GET /health Health check\n\nUsage:\n curl -X POST http://localhost:${port}/generate \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"html\": \"<html>...</html>\"}' \\\\\n -o output.pdf\n\nFor development with live preview, use:\n npx pdfn dev\n`);\n });\n\n return {\n app,\n start: async () => {\n // Pre-launch browser\n logger.browser(\"launching\");\n await browserManager.getBrowser();\n logger.browser(\"ready\");\n\n return new Promise((resolve, reject) => {\n server = app.listen(port, () => {\n logger.banner(port, maxConcurrent, timeout);\n resolve();\n });\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n logger.error(`Port ${port} is already in use`);\n logger.info(`Either stop the existing server or use a different port`);\n process.exit(1);\n }\n reject(err);\n });\n });\n },\n stop: async () => {\n await browserManager.close();\n logger.browser(\"closed\");\n\n if (server) {\n await new Promise<void>((resolve) => {\n server!.close(() => resolve());\n });\n server = null;\n }\n\n logger.success(\"Server stopped\");\n },\n };\n}\n\n// Re-export types\nexport type { PdfGenerationOptions, PdfResult } from \"./pdf\";\nexport type { BrowserManagerOptions } from \"./browser\";\nexport { createBaseServer, type BaseServerOptions, type BaseServer } from \"./base\";\n","import { Command } from \"commander\";\nimport { existsSync, mkdirSync, copyFileSync, readFileSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport chalk from \"chalk\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Available templates with descriptions\nconst TEMPLATES: Record<string, { name: string; description: string; pageSize: string }> = {\n invoice: {\n name: \"Invoice\",\n description: \"Professional invoice with itemized billing\",\n pageSize: \"A4\",\n },\n letter: {\n name: \"Business Letter\",\n description: \"US business correspondence\",\n pageSize: \"Letter\",\n },\n contract: {\n name: \"Contract\",\n description: \"Legal service agreement with terms\",\n pageSize: \"Legal\",\n },\n ticket: {\n name: \"Event Ticket\",\n description: \"Admission ticket with QR placeholder\",\n pageSize: \"A5\",\n },\n poster: {\n name: \"Poster\",\n description: \"Event poster (landscape)\",\n pageSize: \"Tabloid\",\n },\n};\n\ntype TemplateStyle = \"inline\" | \"tailwind\";\n\nfunction getTemplatesDir(style: TemplateStyle): string {\n // After build, cli.js is in dist/, templates are in templates/\n // So from dist/ we go up one level to package root, then into templates/<style>/\n return join(__dirname, \"..\", \"templates\", style);\n}\n\n/**\n * Check if @pdfn/tailwind is installed in user's project\n * Checks both package.json and node_modules for compatibility with npm, pnpm, yarn\n */\nfunction isTailwindInstalled(cwd: string): boolean {\n // First check package.json for explicit dependency\n try {\n const pkgPath = join(cwd, \"package.json\");\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n if (pkg.dependencies?.[\"@pdfn/tailwind\"] || pkg.devDependencies?.[\"@pdfn/tailwind\"]) {\n return true;\n }\n }\n } catch {\n // Ignore parse errors\n }\n\n // Fall back to checking node_modules (for linked packages, global installs, etc.)\n const tailwindPath = join(cwd, \"node_modules\", \"@pdfn\", \"tailwind\");\n return existsSync(tailwindPath);\n}\n\nexport const addCommand = new Command(\"add\")\n .description(\"Add a starter template to your project\")\n .argument(\"[template]\", \"Template name (e.g., invoice, letter, contract)\")\n .option(\"--list\", \"List available templates\")\n .option(\"--tailwind\", \"Use Tailwind CSS styling (requires @pdfn/tailwind)\")\n .option(\"--inline\", \"Use inline styles (default)\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (template, options) => {\n const cwd = process.cwd();\n const outputDir = \"./pdfn-templates\";\n\n // List templates\n if (options.list || !template) {\n console.log(chalk.bold(\"\\nAvailable templates:\\n\"));\n\n for (const [id, info] of Object.entries(TEMPLATES)) {\n console.log(` ${chalk.cyan(id.padEnd(12))} ${info.description} ${chalk.dim(`(${info.pageSize})`)}`);\n }\n\n console.log(chalk.dim(\"\\nUsage: pdfn add <template> [--tailwind]\"));\n console.log(chalk.dim(\"Example: pdfn add invoice\"));\n console.log(chalk.dim(\"Example: pdfn add invoice --tailwind\\n\"));\n console.log(chalk.bold(\"Options:\"));\n console.log(chalk.dim(\" --inline Use inline styles (default)\"));\n console.log(chalk.dim(\" --tailwind Use Tailwind CSS (requires @pdfn/tailwind)\\n\"));\n return;\n }\n\n // Validate template\n if (!TEMPLATES[template]) {\n console.error(chalk.red(`\\nError: Unknown template \"${template}\"`));\n console.log(chalk.dim(\"Run 'pdfn add --list' to see available templates\\n\"));\n process.exit(1);\n }\n\n // Determine style (default to inline)\n const style: TemplateStyle = options.tailwind ? \"tailwind\" : \"inline\";\n\n // Check for @pdfn/tailwind if tailwind style requested\n if (style === \"tailwind\" && !isTailwindInstalled(cwd)) {\n console.error(chalk.yellow(`\\n⚠ @pdfn/tailwind is not installed.`));\n console.log(chalk.dim(\"Install it first to use Tailwind templates:\\n\"));\n console.log(chalk.cyan(\" npm install @pdfn/tailwind\\n\"));\n console.log(chalk.dim(\"Or use inline styles (default):\\n\"));\n console.log(chalk.cyan(` pdfn add ${template}\\n`));\n process.exit(1);\n }\n\n const templatesDir = getTemplatesDir(style);\n const sourceFile = join(templatesDir, `${template}.tsx`);\n const outputFile = join(outputDir, `${template}.tsx`);\n\n // Check if source template exists\n if (!existsSync(sourceFile)) {\n console.error(chalk.red(`\\nError: Template file not found: ${sourceFile}`));\n console.log(chalk.dim(\"This may be a package installation issue.\\n\"));\n process.exit(1);\n }\n\n // Create output directory\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n console.log(chalk.dim(`Created ${outputDir}/`));\n }\n\n // Check if file already exists\n if (existsSync(outputFile) && !options.force) {\n console.error(chalk.yellow(`\\nFile already exists: ${outputFile}`));\n console.log(chalk.dim(\"Use --force to overwrite\\n\"));\n process.exit(1);\n }\n\n // Copy template\n try {\n copyFileSync(sourceFile, outputFile);\n\n const info = TEMPLATES[template];\n const styleLabel = style === \"tailwind\" ? chalk.cyan(\" (Tailwind)\") : chalk.dim(\" (inline styles)\");\n console.log(chalk.green(`\\n✓ Added ${info.name} template`) + styleLabel);\n console.log(chalk.dim(` ${outputFile}\\n`));\n\n // Show next steps\n console.log(chalk.bold(\"Next steps:\"));\n console.log(chalk.dim(` 1. Edit ${outputFile} to customize`));\n console.log(chalk.dim(` 2. Run 'npx pdfn dev' to preview\\n`));\n\n // Additional info for tailwind\n if (style === \"tailwind\") {\n console.log(chalk.dim(\"Note: Tailwind templates require @pdfn/tailwind to be installed.\\n\"));\n }\n } catch (error) {\n console.error(chalk.red(`\\nError copying template: ${error}`));\n process.exit(1);\n }\n });\n\n// Also export the template info for use by dev server\nexport { TEMPLATES };\n"],"mappings":";;;AAAA,SAAS,WAAAA,gBAAe;;;ACAxB,SAAS,eAAe;AACxB,SAAS,cAAAC,aAAY,aAAa,oBAAoB;AACtD,SAAS,MAAM,WAAAC,gBAAe;AAE9B,SAAS,gBAAgB,wBAAwB;AACjD,SAAS,iBAAiB,iBAAiB;AAC3C,OAAO,cAAc;AACrB,SAAS,gBAAgB,wBAAwB;AACjD,SAAS,aAAa;AACtB,OAAOC,gBAAe;;;ACTtB,OAAO,aAAa;;;ACApB,OAAO,eAAkC;AAiBlC,IAAM,iBAAN,MAAqB;AAAA,EAClB,UAA0B;AAAA,EAC1B,YAAqC;AAAA,EACrC,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EAER,YAAY,UAAiC,CAAC,GAAG;AAC/C,SAAK,gBACH,QAAQ,iBACR,SAAS,QAAQ,IAAI,uBAAuB,KAAK,EAAE;AACrD,SAAK,UACH,QAAQ,WAAW,SAAS,QAAQ,IAAI,gBAAgB,SAAS,EAAE;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA+B;AACnC,QAAI,KAAK,SAAS,WAAW;AAC3B,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,KAAK,WAAW;AAClB,aAAO,KAAK;AAAA,IACd;AAGA,SAAK,YAAY,UAAU,OAAO;AAAA,MAChC,UAAU;AAAA,MACV,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI;AACF,WAAK,UAAU,MAAM,KAAK;AAC1B,WAAK,sBAAsB,KAAK,OAAO;AACvC,aAAO,KAAK;AAAA,IACd,UAAE;AACA,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,SAAwB;AACpD,YAAQ,GAAG,gBAAgB,MAAM;AAC/B,WAAK,UAAU;AAAA,IAEjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,UAAM,UAAU,MAAM,KAAK,WAAW;AACtC,UAAM,OAAO,MAAM,QAAQ,QAAQ;AACnC,SAAK,kBAAkB,KAAK,OAAO;AACnC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,SAAY,IAA4C;AAC5D,QAAI,KAAK,eAAe,KAAK,eAAe;AAC1C,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,SAAK;AACL,QAAI,OAAoB;AAExB,QAAI;AACF,aAAO,MAAM,KAAK,WAAW;AAC7B,aAAO,MAAM,GAAG,IAAI;AAAA,IACtB,UAAE;AACA,WAAK;AACL,UAAI,MAAM;AACR,cAAM,KAAK,MAAM,EAAE,MAAM,MAAM;AAAA,QAE/B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,SAAS,aAAa;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAyB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,aAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,QAAI,KAAK,SAAS;AAChB,YAAM,KAAK,QAAQ,MAAM;AACzB,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AACF;;;AClJA,IAAM,WAAW,QAAQ,IAAI,SAAS;AACtC,IAAM,YACJ,SAAS,SAAS,UAAU,KAC5B,SAAS,SAAS,QAAQ,KAC1B,aAAa,UACb,SAAS,SAAS,OAAO,KACzB,SAAS,SAAS,OAAO;AAKpB,IAAM,QAAQ,YACjB,CAAC,YAAoB,SAAoB;AACvC,UAAQ,IAAI,cAAc,OAAO,IAAI,GAAG,IAAI;AAC9C,IACA,MAAM;AAAC;;;AC4BX,IAAM,wBAAwB,MAAM;AAGpC,IAAM,uBAAuB;AAG7B,SAAS,aAAa,cAAyC;AAC7D,UAAQ,cAAc;AAAA,IACpB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAGA,SAAS,YAAY,KAAqB;AACxC,MAAI,IAAI,WAAW,OAAO,GAAG;AAC3B,UAAM,QAAQ,IAAI,MAAM,gBAAgB;AACxC,WAAO,QAAQ,QAAQ,MAAM,CAAC,CAAC,QAAQ;AAAA,EACzC;AACA,MAAI,IAAI,SAAS,IAAI;AACnB,WAAO,IAAI,UAAU,GAAG,EAAE,IAAI;AAAA,EAChC;AACA,SAAO;AACT;AAKA,eAAsB,YACpB,MACA,MACA,UAAgC,CAAC,GACb;AACpB,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,kBAAkB;AAAA,IAClB,UAAU;AAAA,EACZ,IAAI;AAEJ,QAAM,YAAY,YAAY,IAAI;AAClC,MAAI,kBAAkB;AACtB,MAAI,cAAc;AAClB,MAAI,iBAAiB;AACrB,MAAI,YAAY;AAGhB,QAAM,SAAsB,CAAC;AAC7B,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,WAAqB,CAAC;AAG5B,QAAM,YAAY,CAAC,YAAyB;AAC1C,UAAM,MAAM,QAAQ,IAAI;AACxB,UAAM,eAAe,QAAQ,aAAa;AAG1C,QAAI,CAAC,SAAS,QAAQ,cAAc,QAAQ,EAAE,SAAS,YAAY,GAAG;AACpE,wBAAkB,IAAI,KAAK,YAAY,IAAI,CAAC;AAAA,IAC9C;AAAA,EACF;AAGA,QAAM,aAAa,CAAC,aAA2B;AAC7C,UAAM,MAAM,SAAS,IAAI;AACzB,UAAM,UAAU,SAAS,QAAQ;AACjC,UAAM,eAAe,QAAQ,aAAa;AAC1C,UAAMC,aAAY,kBAAkB,IAAI,GAAG;AAE3C,QAAIA,eAAc,OAAW;AAE7B,UAAM,WAAW,KAAK,MAAM,YAAY,IAAI,IAAIA,UAAS;AACzD,UAAM,SAAS,SAAS,OAAO;AAC/B,UAAM,UAAU,UAAU,OAAO,SAAS;AAG1C,UAAM,gBAAgB,SAAS,QAAQ,EAAE,gBAAgB;AACzD,UAAM,OAAO,gBAAgB,SAAS,eAAe,EAAE,IAAI;AAE3D,UAAM,QAAmB;AAAA,MACvB,KAAK,YAAY,GAAG;AAAA,MACpB,MAAM,aAAa,YAAY;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ,YAAM,QAAQ,QAAQ,MAAM;AAC5B,eAAS,KAAK,WAAW,MAAM,GAAG,KAAK,MAAM,GAAG;AAAA,IAClD,OAAO;AACL,UAAI,OAAO,uBAAuB;AAChC,iBAAS,KAAK,UAAU,MAAM,GAAG,MAAM,OAAO,MAAM,QAAQ,CAAC,CAAC,KAAK;AAAA,MACrE;AACA,UAAI,WAAW,sBAAsB;AACnC,iBAAS,KAAK,SAAS,MAAM,GAAG,KAAK,QAAQ,KAAK;AAAA,MACpD;AAAA,IACF;AAEA,WAAO,KAAK,KAAK;AACjB,sBAAkB,OAAO,GAAG;AAAA,EAC9B;AAGA,QAAM,kBAAkB,CAAC,YAAyB;AAChD,UAAM,MAAM,QAAQ,IAAI;AACxB,UAAM,eAAe,QAAQ,aAAa;AAC1C,UAAMA,aAAY,kBAAkB,IAAI,GAAG;AAE3C,QAAIA,eAAc,OAAW;AAE7B,UAAM,WAAW,KAAK,MAAM,YAAY,IAAI,IAAIA,UAAS;AACzD,UAAM,UAAU,QAAQ,QAAQ;AAChC,UAAM,YAAY,SAAS,aAAa;AAExC,UAAM,QAAmB;AAAA,MACvB,KAAK,YAAY,GAAG;AAAA,MACpB,MAAM,aAAa,YAAY;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAEA,aAAS,KAAK,WAAW,MAAM,GAAG,KAAK,SAAS,GAAG;AACnD,WAAO,KAAK,KAAK;AACjB,sBAAkB,OAAO,GAAG;AAAA,EAC9B;AAGA,OAAK,GAAG,WAAW,SAAS;AAC5B,OAAK,GAAG,YAAY,UAAU;AAC9B,OAAK,GAAG,iBAAiB,eAAe;AAExC,MAAI;AAEF,UAAM,eAAe,YAAY,IAAI;AACrC,UAAM,KAAK,WAAW,MAAM;AAAA,MAC1B,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AACD,sBAAkB,YAAY,IAAI,IAAI;AAGtC,UAAM,aAAa,YAAY,IAAI;AACnC,UAAM,KAAK;AAAA,MACT,MAAO,OAAe,MAAM,UAAU;AAAA,MACtC,EAAE,QAAQ;AAAA,IACZ;AACA,kBAAc,YAAY,IAAI,IAAI;AAGlC,gBAAY,MAAM,KAAK,SAAS,MAAM;AACpC,aAAQ,OAAe,MAAM,SAAS,SAAS;AAAA,IACjD,CAAC;AAGD,UAAM,WAAW,YAAY,IAAI;AACjC,UAAM,aAAyB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,QAAQ;AAAA;AAAA,MACR,SAAS;AAAA;AAAA,IACX;AAEA,UAAM,SAAS,MAAM,KAAK,IAAI,UAAU;AACxC,qBAAiB,YAAY,IAAI,IAAI;AAErC,UAAM,YAAY,YAAY,IAAI,IAAI;AACtC,UAAM,YAAY,OAAO,KAAK,MAAM;AAEpC;AAAA,MACE,QAAQ,KAAK,MAAM,SAAS,CAAC,aAAa,KAAK,MAAM,eAAe,CAAC,cAAc,KAAK,MAAM,WAAW,CAAC,gBAAgB,KAAK,MAAM,cAAc,CAAC,SAAS,SAAS,YAAY,UAAU,SAAS,MAAM,QAAQ,CAAC,CAAC;AAAA,IACvN;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,WAAW,OAAO,MAAM,KAAK,OAAO,OAAO,OAAK,CAAC,EAAE,OAAO,EAAE,MAAM,UAAU;AAAA,IACpF;AAEA,QAAI,SAAS,SAAS,GAAG;AACvB,eAAS,QAAQ,OAAK,MAAM,YAAY,CAAC,EAAE,CAAC;AAAA,IAC9C;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,OAAO,KAAK,MAAM,SAAS;AAAA,QAC3B,aAAa,KAAK,MAAM,eAAe;AAAA,QACvC,SAAS,KAAK,MAAM,WAAW;AAAA,QAC/B,YAAY,KAAK,MAAM,cAAc;AAAA,QACrC;AAAA,QACA,SAAS,UAAU;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,UAAE;AAEA,SAAK,IAAI,WAAW,SAAS;AAC7B,SAAK,IAAI,YAAY,UAAU;AAC/B,SAAK,IAAI,iBAAiB,eAAe;AAGzC,UAAM,KAAK,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnC;AACF;;;ACxOO,SAAS,sBACd,gBACA,UAAkC,CAAC,GACnC;AACA,QAAM,EAAE,UAAU,KAAO,WAAW,QAAQ,IAAI;AAEhD,SAAO,OAAO,KAAc,QAAkB;AAC5C,UAAM,EAAE,MAAM,SAAS,WAAW,IAAI,IAAI;AAC1C,UAAM,SAAS,IAAI,MAAM;AAEzB,QAAI,CAAC,MAAM;AACT,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAC1D;AAAA,IACF;AAGA,QAAI,WAAW,QAAQ;AACrB,UAAI,UAAU,gBAAgB,0BAA0B;AACxD,UAAI,KAAK,IAAI;AACb;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,eAAe,SAAS,OAAO,SAAS;AAC3D,eAAO,YAAY,MAAM,MAAM;AAAA,UAC7B,GAAG;AAAA,UACH,SAAS,YAAY,WAAW;AAAA,QAClC,CAAC;AAAA,MACH,CAAC;AAGD,UAAI,UAAU,gBAAgB,iBAAiB;AAC/C,UAAI,UAAU,qBAAqB,OAAO,QAAQ,MAAM,SAAS,CAAC;AAClE,UAAI,UAAU,uBAAuB,OAAO,QAAQ,YAAY,SAAS,CAAC;AAC1E,UAAI,UAAU,uBAAuB,OAAO,QAAQ,QAAQ,SAAS,CAAC;AACtE,UAAI,UAAU,sBAAsB,OAAO,QAAQ,WAAW,SAAS,CAAC;AACxE,UAAI,UAAU,qBAAqB,OAAO,QAAQ,UAAU,SAAS,CAAC;AACtE,UAAI,UAAU,mBAAmB,OAAO,QAAQ,QAAQ,SAAS,CAAC;AAGlE,MAAC,IAAY,aAAa;AAG1B,kBAAY,MAAM;AAElB,UAAI,KAAK,OAAO,MAAM;AAAA,IACxB,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AAGzD,gBAAU,OAAO;AAEjB,UAAI,QAAQ,SAAS,aAAa,GAAG;AACnC,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,QAAQ,CAAC;AACvC;AAAA,MACF;AAEA,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,QAAQ,CAAC;AAAA,IACzC;AAAA,EACF;AACF;;;AJpDO,SAAS,iBAAiB,UAA6B,CAAC,GAAe;AAC5E,QAAM,gBACJ,QAAQ,iBACR,SAAS,QAAQ,IAAI,uBAAuB,KAAK,EAAE;AACrD,QAAM,UACJ,QAAQ,WAAW,SAAS,QAAQ,IAAI,gBAAgB,SAAS,EAAE;AACrE,QAAM,gBAAgB,QAAQ,iBAAiB;AAE/C,QAAM,MAAM,QAAQ;AACpB,QAAM,iBAAiB,IAAI,eAAe,EAAE,eAAe,QAAQ,CAAC;AAGpE,MAAI,IAAI,QAAQ,KAAK,EAAE,OAAO,OAAO,CAAC,CAAC;AAGvC,MAAI,iBAAiB,QAAQ,WAAW;AACtC,UAAM,YAAY,QAAQ;AAC1B,UAAM,cAAc,QAAQ;AAE5B,QAAI,IAAI,CAAC,KAAc,KAAe,SAAuB;AAE3D,YAAM,YAAY,CAAC,gBAAgB,aAAa;AAChD,UAAI,UAAU,SAAS,IAAI,IAAI,GAAG;AAChC,aAAK;AACL;AAAA,MACF;AAEA,YAAM,QAAQ,YAAY,IAAI;AAE9B,UAAI,GAAG,UAAU,MAAM;AACrB,cAAM,WAAW,YAAY,IAAI,IAAI;AAGrC,YAAI;AACJ,YAAI,IAAI,SAAS,eAAe,IAAI,eAAe,KAAK;AACtD,gBAAM,QAAQ,IAAI,UAAU,mBAAmB;AAC/C,gBAAM,OAAO,OAAO,IAAI,UAAU,iBAAiB,CAAC,KAAK;AACzD,gBAAM,UAAU,OAAO,MAAM,QAAQ,CAAC;AACtC,kBAAQ,GAAG,KAAK,iBAAY,MAAM;AAAA,QACpC;AAEA,kBAAU,IAAI,QAAQ,IAAI,MAAM,IAAI,YAAY,UAAU,KAAK;AAG/D,cAAM,YAAa,IAAY;AAC/B,YAAI,aAAa,aAAa;AAC5B,sBAAY,SAAS;AAAA,QACvB;AAAA,MACF,CAAC;AAED,WAAK;AAAA,IACP,CAAC;AAAA,EACH;AAGA,MAAI,IAAI,WAAW,CAAC,MAAe,QAAkB;AACnD,QAAI,KAAK;AAAA,MACP,QAAQ;AAAA,MACR,SAAS,eAAe,YAAY,IAAI,cAAc;AAAA,MACtD,aAAa,eAAe,eAAe;AAAA,MAC3C,eAAe,eAAe,iBAAiB;AAAA,IACjD,CAAC;AAAA,EACH,CAAC;AAGD,MAAI;AAAA,IACF;AAAA,IACA,sBAAsB,gBAAgB;AAAA,MACpC;AAAA,MACA,WAAW,QAAQ;AAAA,MACnB,SAAS,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AD7GA,SAAS,oBAAoB;AAC7B,OAAO,WAAW;;;AMdlB,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,cAAc;AAShB,SAAS,QAAQ,MAAoB;AAC1C,QAAM,MAAM,QAAQ,IAAI;AAGxB,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,EACd;AAEA,aAAW,QAAQ,UAAU;AAC3B,UAAM,WAAW,QAAQ,KAAK,IAAI;AAClC,QAAI,WAAW,QAAQ,GAAG;AAExB,aAAO,EAAE,MAAM,UAAU,UAAU,MAAM,OAAO,KAAK,CAAC;AAAA,IACxD;AAAA,EACF;AACF;;;ANDA,IAAM,gBAAgB;AAQtB,eAAe,cAAc,cAA+C;AAC1E,MAAI,CAACC,YAAW,YAAY,GAAG;AAC7B,WAAO,CAAC;AAAA,EACV;AAGA,MAAI,aAAsD,CAAC;AAC3D,QAAM,cAAc;AAAA,IAClB,KAAK,QAAQ,IAAI,GAAG,OAAO,UAAU,gBAAgB;AAAA,IACrD,KAAK,QAAQ,IAAI,GAAG,gBAAgB;AAAA,IACpC,KAAK,cAAc,gBAAgB;AAAA,EACrC;AAEA,aAAW,cAAc,aAAa;AACpC,QAAIA,YAAW,UAAU,GAAG;AAC1B,UAAI;AACF,cAAMC,UAAS,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AAC3D,YAAIA,QAAO,aAAa,MAAM,QAAQA,QAAO,SAAS,GAAG;AACvD,qBAAW,KAAKA,QAAO,WAAW;AAChC,gBAAI,EAAE,MAAM,EAAE,YAAY;AACxB,yBAAW,EAAE,EAAE,IAAI,EAAE;AAAA,YACvB;AAAA,UACF;AAAA,QACF;AACA;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,YAAY,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,CAAC;AAIxE,QAAM,YAA4B,CAAC;AAEnC,aAAW,QAAQ,OAAO;AACxB,UAAM,KAAK,KAAK,QAAQ,QAAQ,EAAE;AAClC,UAAM,WAAW,KAAK,cAAc,IAAI;AAGxC,QAAI;AACF,YAAM,UAAU,aAAa,UAAU,OAAO;AAE9C,UAAI,CAAC,QAAQ,SAAS,gBAAgB,KAAK,CAAC,QAAQ,SAAS,UAAU,GAAG;AACxE;AAAA,MACF;AAEA,UAAI,CAAC,QAAQ,SAAS,UAAU,KAAK,CAAC,QAAQ,SAAS,MAAM,GAAG;AAC9D;AAAA,MACF;AAAA,IACF,QAAQ;AACN;AAAA,IACF;AAGA,UAAM,OAAO,GACV,MAAM,MAAM,EACZ,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,CAAC,EACjD,KAAK,GAAG;AAEX,cAAU,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,YAAY,WAAW,EAAE;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,WAA2B,gBAAuC;AAC3F,QAAM,eAAe,UAClB;AAAA,IACC,CAAC,MAAM;AAAA;AAAA,8BAEiB,EAAE,OAAO,iBAAiB,WAAW,EAAE;AAAA,yBAC5C,EAAE,EAAE;AAAA,qBACR,EAAE,IAAI;AAAA;AAAA,sCAEW,EAAE,IAAI;AAAA;AAAA;AAAA,EAGxC,EACC,KAAK,EAAE;AAEV,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAseD,UAAU,SAAS,IACf,eACA,uFACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YA8BM,iBACI,kGACA,+GACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BA8FkB,iBAAiB,IAAI,cAAc,MAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["Command","existsSync","resolve","puppeteer","startTime","existsSync","config","resolve","options","puppeteer","Command","resolve","Command","Command","existsSync","readFileSync","join","chalk","Command"]}
|