pdf-smith 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +72 -0
- package/dist/index.cjs +9 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/preview-plugin-26BUIGCE.js +199 -0
- package/dist/preview-plugin-26BUIGCE.js.map +1 -0
- package/dist/server.cjs +215 -50
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +5 -7
- package/dist/server.d.ts +5 -7
- package/dist/server.js +75 -25
- package/dist/server.js.map +1 -1
- package/package.json +9 -2
- package/src/add.ts +72 -0
- package/src/cli.ts +24 -0
- package/src/config.ts +8 -0
- package/src/index.ts +2 -0
- package/src/preview/app.tsx +278 -39
- package/src/preview/design-tokens.ts +42 -0
- package/src/preview/entry.tsx +7 -3
- package/src/preview/home.tsx +550 -0
- package/src/preview/icons.tsx +250 -0
- package/src/preview/navigation.tsx +328 -73
- package/src/preview/preview-plugin.ts +161 -20
- package/src/preview/types.ts +0 -2
- package/src/preview/vite-env.d.ts +8 -2
- package/dist/preview-plugin-QWJEXDW2.js +0 -84
- package/dist/preview-plugin-QWJEXDW2.js.map +0 -1
package/dist/server.cjs
CHANGED
|
@@ -31,10 +31,39 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
33
|
// src/export.ts
|
|
34
|
+
function discoverDocuments(root) {
|
|
35
|
+
const pdfsDir = import_node_path.default.join(root, "pdfs");
|
|
36
|
+
if (!import_node_fs.default.existsSync(pdfsDir)) return [];
|
|
37
|
+
const entries = import_node_fs.default.readdirSync(pdfsDir, { withFileTypes: true });
|
|
38
|
+
const documents = [];
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
if (!entry.isDirectory()) continue;
|
|
41
|
+
const pagesDir = import_node_path.default.join(pdfsDir, entry.name, "pages");
|
|
42
|
+
if (!import_node_fs.default.existsSync(pagesDir)) continue;
|
|
43
|
+
const configPath = import_node_path.default.join(pdfsDir, entry.name, "config.ts");
|
|
44
|
+
documents.push({
|
|
45
|
+
slug: entry.name,
|
|
46
|
+
configPath: import_node_fs.default.existsSync(configPath) ? configPath : null
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return documents;
|
|
50
|
+
}
|
|
34
51
|
async function exportPDF(options) {
|
|
35
|
-
const { root,
|
|
36
|
-
const
|
|
37
|
-
|
|
52
|
+
const { root, document: documentSlug, output } = options;
|
|
53
|
+
const outputDir = import_node_path.default.resolve(root, output ?? "output");
|
|
54
|
+
let documents = discoverDocuments(root);
|
|
55
|
+
if (documentSlug) {
|
|
56
|
+
documents = documents.filter((d) => d.slug === documentSlug);
|
|
57
|
+
if (documents.length === 0) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Document "${documentSlug}" not found. Check that pdfs/${documentSlug}/pages/ exists.`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (documents.length === 0) {
|
|
64
|
+
throw new Error("No documents found. Create at least one document in pdfs/<name>/pages/.");
|
|
65
|
+
}
|
|
66
|
+
import_node_fs.default.mkdirSync(outputDir, { recursive: true });
|
|
38
67
|
let playwright;
|
|
39
68
|
try {
|
|
40
69
|
playwright = await import("playwright");
|
|
@@ -44,33 +73,49 @@ async function exportPDF(options) {
|
|
|
44
73
|
);
|
|
45
74
|
}
|
|
46
75
|
const { startPreview: startPreview2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
47
|
-
const server = await startPreview2({ root, port: 0,
|
|
76
|
+
const server = await startPreview2({ root, port: 0, open: false });
|
|
77
|
+
const vite = server._vite;
|
|
48
78
|
const browser = await playwright.chromium.launch({ headless: true });
|
|
79
|
+
const outputs = [];
|
|
49
80
|
try {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
margin
|
|
81
|
+
for (const doc of documents) {
|
|
82
|
+
let config;
|
|
83
|
+
if (doc.configPath && vite) {
|
|
84
|
+
try {
|
|
85
|
+
const configModule = await vite.ssrLoadModule(doc.configPath);
|
|
86
|
+
config = configModule.default;
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const filename = config?.output ?? `${doc.slug}.pdf`;
|
|
91
|
+
const outputPath = import_node_path.default.resolve(outputDir, filename);
|
|
92
|
+
const page = await browser.newPage();
|
|
93
|
+
await page.goto(`${server.url}/${doc.slug}`, { waitUntil: "networkidle" });
|
|
94
|
+
await page.waitForSelector("[data-pdf-smith-page]", { timeout: 3e4 });
|
|
95
|
+
const margin = { top: "0", bottom: "0", left: "0", right: "0" };
|
|
96
|
+
const pdfOptions = {
|
|
97
|
+
path: outputPath,
|
|
98
|
+
preferCSSPageSize: true,
|
|
99
|
+
printBackground: true,
|
|
100
|
+
margin
|
|
101
|
+
};
|
|
102
|
+
if (config?.pageNumbers?.enabled) {
|
|
103
|
+
pdfOptions.displayHeaderFooter = true;
|
|
104
|
+
pdfOptions.headerTemplate = "<span></span>";
|
|
105
|
+
pdfOptions.footerTemplate = config.pageNumbers.template ?? '<div style="font-size:10px;text-align:center;width:100%;"><span class="pageNumber"></span> / <span class="totalPages"></span></div>';
|
|
106
|
+
margin.bottom = "40px";
|
|
107
|
+
}
|
|
108
|
+
await page.pdf(pdfOptions);
|
|
109
|
+
await page.close();
|
|
110
|
+
outputs.push({ document: doc.slug, outputPath });
|
|
65
111
|
}
|
|
66
|
-
await page.pdf(pdfOptions);
|
|
67
112
|
} finally {
|
|
68
113
|
await browser.close().catch(() => {
|
|
69
114
|
});
|
|
70
115
|
await server.close().catch(() => {
|
|
71
116
|
});
|
|
72
117
|
}
|
|
73
|
-
return {
|
|
118
|
+
return { outputs };
|
|
74
119
|
}
|
|
75
120
|
var import_node_fs, import_node_path;
|
|
76
121
|
var init_export = __esm({
|
|
@@ -86,13 +131,90 @@ var preview_plugin_exports = {};
|
|
|
86
131
|
__export(preview_plugin_exports, {
|
|
87
132
|
pdfSmithPreviewPlugin: () => pdfSmithPreviewPlugin
|
|
88
133
|
});
|
|
89
|
-
function
|
|
134
|
+
async function handleExportRequest(server, slug, res) {
|
|
135
|
+
const root = server.config.root;
|
|
136
|
+
const pagesDir = import_node_path2.default.join(root, "pdfs", slug, "pages");
|
|
137
|
+
if (!import_node_fs2.default.existsSync(pagesDir)) {
|
|
138
|
+
res.statusCode = 404;
|
|
139
|
+
res.setHeader("Content-Type", "application/json");
|
|
140
|
+
res.end(JSON.stringify({ error: `Document "${slug}" not found` }));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
let config;
|
|
144
|
+
const configPath = import_node_path2.default.join(root, "pdfs", slug, "config.ts");
|
|
145
|
+
if (import_node_fs2.default.existsSync(configPath)) {
|
|
146
|
+
try {
|
|
147
|
+
const configModule = await server.ssrLoadModule(configPath);
|
|
148
|
+
config = configModule.default;
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
let playwright;
|
|
153
|
+
try {
|
|
154
|
+
playwright = await import("playwright");
|
|
155
|
+
} catch {
|
|
156
|
+
res.statusCode = 500;
|
|
157
|
+
res.setHeader("Content-Type", "application/json");
|
|
158
|
+
res.end(
|
|
159
|
+
JSON.stringify({
|
|
160
|
+
error: "Playwright is required for PDF export. Install it with: npm install -D playwright && npx playwright install chromium"
|
|
161
|
+
})
|
|
162
|
+
);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
let browser;
|
|
166
|
+
try {
|
|
167
|
+
const address = server.httpServer?.address();
|
|
168
|
+
const port = address?.port;
|
|
169
|
+
if (!port) throw new Error("Could not determine server port");
|
|
170
|
+
browser = await playwright.chromium.launch({ headless: true });
|
|
171
|
+
const page = await browser.newPage();
|
|
172
|
+
await page.goto(`http://localhost:${port}/${slug}`, { waitUntil: "networkidle" });
|
|
173
|
+
await page.waitForSelector("[data-pdf-smith-page]", { timeout: 3e4 });
|
|
174
|
+
const margin = { top: "0", bottom: "0", left: "0", right: "0" };
|
|
175
|
+
const pdfOptions = {
|
|
176
|
+
preferCSSPageSize: true,
|
|
177
|
+
printBackground: true,
|
|
178
|
+
margin
|
|
179
|
+
};
|
|
180
|
+
if (config?.pageNumbers?.enabled) {
|
|
181
|
+
pdfOptions.displayHeaderFooter = true;
|
|
182
|
+
pdfOptions.headerTemplate = "<span></span>";
|
|
183
|
+
pdfOptions.footerTemplate = config.pageNumbers.template ?? '<div style="font-size:10px;text-align:center;width:100%;"><span class="pageNumber"></span> / <span class="totalPages"></span></div>';
|
|
184
|
+
margin.bottom = "40px";
|
|
185
|
+
}
|
|
186
|
+
const buffer = await page.pdf(pdfOptions);
|
|
187
|
+
await page.close();
|
|
188
|
+
const filename = config?.output ?? `${slug}.pdf`;
|
|
189
|
+
res.statusCode = 200;
|
|
190
|
+
res.setHeader("Content-Type", "application/pdf");
|
|
191
|
+
res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
|
|
192
|
+
res.end(buffer);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
if (!res.headersSent) {
|
|
195
|
+
res.statusCode = 500;
|
|
196
|
+
res.setHeader("Content-Type", "application/json");
|
|
197
|
+
res.end(JSON.stringify({ error: err instanceof Error ? err.message : "PDF export failed" }));
|
|
198
|
+
}
|
|
199
|
+
} finally {
|
|
200
|
+
await browser?.close().catch(() => {
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function pdfSmithPreviewPlugin({ pkgSrcDir }) {
|
|
90
205
|
return {
|
|
91
206
|
name: "pdf-smith-preview",
|
|
92
207
|
configureServer(server) {
|
|
208
|
+
server.middlewares.use((req, res, next) => {
|
|
209
|
+
if (req.method !== "POST") return next();
|
|
210
|
+
const match = req.url?.match(/^\/api\/export\/([^/]+)$/);
|
|
211
|
+
if (!match) return next();
|
|
212
|
+
void handleExportRequest(server, match[1], res);
|
|
213
|
+
});
|
|
93
214
|
return () => {
|
|
94
215
|
server.middlewares.use((req, res, next) => {
|
|
95
|
-
|
|
216
|
+
const url = req.url ?? "";
|
|
217
|
+
if (url.includes(".") || url.startsWith("/@") || url.startsWith("/node_modules/")) {
|
|
96
218
|
next();
|
|
97
219
|
return;
|
|
98
220
|
}
|
|
@@ -110,18 +232,35 @@ window.__vite_plugin_react_preamble_installed__ = true
|
|
|
110
232
|
<meta charset="UTF-8" />
|
|
111
233
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
112
234
|
<title>pdf-smith Preview</title>
|
|
235
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
236
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
237
|
+
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght,SOFT,WONK@0,9..144,100..900,0..100,0..1&family=Inter:opsz,wght@14..32,100..900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
113
238
|
<style>
|
|
239
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
240
|
+
body {
|
|
241
|
+
margin: 0;
|
|
242
|
+
font-family: 'Inter', system-ui, sans-serif;
|
|
243
|
+
-webkit-font-smoothing: antialiased;
|
|
244
|
+
}
|
|
245
|
+
.pdf-smith-search::placeholder { color: #78716C; }
|
|
114
246
|
@media print {
|
|
115
247
|
[data-pdf-smith-nav] { display: none !important; }
|
|
248
|
+
[data-pdf-smith-toolbar] { display: none !important; }
|
|
249
|
+
[data-pdf-smith-minimap] { display: none !important; }
|
|
116
250
|
[data-pdf-smith-container] {
|
|
117
251
|
margin-left: 0 !important;
|
|
118
252
|
padding: 0 !important;
|
|
253
|
+
padding-top: 0 !important;
|
|
119
254
|
background: none !important;
|
|
120
255
|
}
|
|
121
|
-
[data-pdf-smith-container] >
|
|
256
|
+
[data-pdf-smith-container] > div {
|
|
257
|
+
padding: 0 !important;
|
|
258
|
+
gap: 0 !important;
|
|
259
|
+
}
|
|
260
|
+
[data-pdf-smith-document] > div {
|
|
122
261
|
margin-bottom: 0 !important;
|
|
123
262
|
}
|
|
124
|
-
[data-pdf-smith-
|
|
263
|
+
[data-pdf-smith-document] > div > div:first-child {
|
|
125
264
|
display: none !important;
|
|
126
265
|
}
|
|
127
266
|
}
|
|
@@ -139,36 +278,57 @@ window.__vite_plugin_react_preamble_installed__ = true
|
|
|
139
278
|
};
|
|
140
279
|
},
|
|
141
280
|
resolveId(id) {
|
|
142
|
-
if (id ===
|
|
143
|
-
return
|
|
281
|
+
if (id === VIRTUAL_DOCUMENTS_ID) {
|
|
282
|
+
return RESOLVED_VIRTUAL_DOCUMENTS_ID;
|
|
144
283
|
}
|
|
145
284
|
},
|
|
146
285
|
load(id) {
|
|
147
|
-
if (id ===
|
|
286
|
+
if (id === RESOLVED_VIRTUAL_DOCUMENTS_ID) {
|
|
148
287
|
return `
|
|
149
|
-
const
|
|
288
|
+
const pageModules = import.meta.glob('/pdfs/*/pages/**/*.tsx', { eager: true });
|
|
289
|
+
const configModules = import.meta.glob('/pdfs/*/config.ts', { eager: true });
|
|
290
|
+
|
|
291
|
+
export function getDocuments() {
|
|
292
|
+
const documents = {};
|
|
293
|
+
|
|
294
|
+
for (const [path, mod] of Object.entries(pageModules)) {
|
|
295
|
+
const match = path.match(/^\\/pdfs\\/([^/]+)\\/pages\\/(.+)\\.[^.]+$/);
|
|
296
|
+
if (!match) continue;
|
|
297
|
+
const [, slug, pageName] = match;
|
|
298
|
+
if (!documents[slug]) {
|
|
299
|
+
documents[slug] = { slug, pages: {}, config: undefined };
|
|
300
|
+
}
|
|
301
|
+
documents[slug].pages[pageName] = mod.default;
|
|
302
|
+
}
|
|
150
303
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
304
|
+
for (const [path, mod] of Object.entries(configModules)) {
|
|
305
|
+
const match = path.match(/^\\/pdfs\\/([^/]+)\\/config\\.ts$/);
|
|
306
|
+
if (!match) continue;
|
|
307
|
+
const slug = match[1];
|
|
308
|
+
if (documents[slug]) {
|
|
309
|
+
documents[slug].config = mod.default;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return documents;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function getDocumentSlugs() {
|
|
317
|
+
return Object.keys(getDocuments());
|
|
160
318
|
}
|
|
161
319
|
`;
|
|
162
320
|
}
|
|
163
321
|
}
|
|
164
322
|
};
|
|
165
323
|
}
|
|
166
|
-
var
|
|
324
|
+
var import_node_fs2, import_node_path2, VIRTUAL_DOCUMENTS_ID, RESOLVED_VIRTUAL_DOCUMENTS_ID;
|
|
167
325
|
var init_preview_plugin = __esm({
|
|
168
326
|
"src/preview/preview-plugin.ts"() {
|
|
169
327
|
"use strict";
|
|
170
|
-
|
|
171
|
-
|
|
328
|
+
import_node_fs2 = __toESM(require("fs"), 1);
|
|
329
|
+
import_node_path2 = __toESM(require("path"), 1);
|
|
330
|
+
VIRTUAL_DOCUMENTS_ID = "virtual:pdf-smith-documents";
|
|
331
|
+
RESOLVED_VIRTUAL_DOCUMENTS_ID = `\0${VIRTUAL_DOCUMENTS_ID}`;
|
|
172
332
|
}
|
|
173
333
|
});
|
|
174
334
|
|
|
@@ -180,14 +340,14 @@ __export(server_exports, {
|
|
|
180
340
|
});
|
|
181
341
|
module.exports = __toCommonJS(server_exports);
|
|
182
342
|
async function startPreview(options) {
|
|
183
|
-
const { root, port = 3e3,
|
|
343
|
+
const { root, port = 3e3, open = false } = options;
|
|
184
344
|
const { createServer } = await import("vite");
|
|
185
345
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
186
346
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
187
347
|
const { pdfSmithPreviewPlugin: pdfSmithPreviewPlugin2 } = await Promise.resolve().then(() => (init_preview_plugin(), preview_plugin_exports));
|
|
188
|
-
const currentDir =
|
|
189
|
-
const pkgRoot =
|
|
190
|
-
const pkgSrcDir =
|
|
348
|
+
const currentDir = import_node_path3.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
349
|
+
const pkgRoot = import_node_path3.default.resolve(currentDir, "..");
|
|
350
|
+
const pkgSrcDir = import_node_path3.default.resolve(pkgRoot, "src");
|
|
191
351
|
const server = await createServer({
|
|
192
352
|
configFile: false,
|
|
193
353
|
appType: "custom",
|
|
@@ -202,11 +362,11 @@ async function startPreview(options) {
|
|
|
202
362
|
},
|
|
203
363
|
resolve: {
|
|
204
364
|
alias: {
|
|
205
|
-
"pdf-smith":
|
|
365
|
+
"pdf-smith": import_node_path3.default.resolve(pkgSrcDir, "index.ts")
|
|
206
366
|
},
|
|
207
367
|
dedupe: ["react", "react-dom"]
|
|
208
368
|
},
|
|
209
|
-
plugins: [react(), tailwindcss(), pdfSmithPreviewPlugin2({ pkgSrcDir
|
|
369
|
+
plugins: [react(), tailwindcss(), pdfSmithPreviewPlugin2({ pkgSrcDir })],
|
|
210
370
|
optimizeDeps: {
|
|
211
371
|
include: ["react", "react-dom", "react-dom/client", "react/jsx-runtime"]
|
|
212
372
|
}
|
|
@@ -218,7 +378,7 @@ async function startPreview(options) {
|
|
|
218
378
|
const address = server.httpServer?.address();
|
|
219
379
|
const resolvedPort = address?.port ?? port;
|
|
220
380
|
const url = `http://localhost:${resolvedPort}`;
|
|
221
|
-
|
|
381
|
+
const previewServer = {
|
|
222
382
|
close: async () => {
|
|
223
383
|
const httpServer = server.httpServer;
|
|
224
384
|
httpServer?.closeAllConnections?.();
|
|
@@ -227,11 +387,16 @@ async function startPreview(options) {
|
|
|
227
387
|
port: resolvedPort,
|
|
228
388
|
url
|
|
229
389
|
};
|
|
390
|
+
Object.defineProperty(previewServer, "_vite", {
|
|
391
|
+
value: server,
|
|
392
|
+
enumerable: false
|
|
393
|
+
});
|
|
394
|
+
return previewServer;
|
|
230
395
|
}
|
|
231
|
-
var
|
|
396
|
+
var import_node_path3, import_node_url, import_meta;
|
|
232
397
|
var init_server = __esm({
|
|
233
398
|
"src/server.ts"() {
|
|
234
|
-
|
|
399
|
+
import_node_path3 = __toESM(require("path"), 1);
|
|
235
400
|
import_node_url = require("url");
|
|
236
401
|
init_export();
|
|
237
402
|
import_meta = {};
|
package/dist/server.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/export.ts","../src/preview/preview-plugin.ts","../src/server.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ExportOptions, ExportResult } from './export-types';\n\nexport async function exportPDF(options: ExportOptions): Promise<ExportResult> {\n const { root, output, pageNumbers, pages } = options;\n const outputPath = path.resolve(root, output ?? './output.pdf');\n\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n\n let playwright: typeof import('playwright');\n try {\n playwright = await import('playwright');\n } catch {\n throw new Error(\n 'Playwright is required for PDF export. Install it with: npm install -D playwright && npx playwright install chromium',\n );\n }\n\n const { startPreview } = await import('./server');\n const server = await startPreview({ root, port: 0, pages, open: false });\n\n const browser = await playwright.chromium.launch({ headless: true });\n try {\n const page = await browser.newPage();\n await page.goto(server.url, { waitUntil: 'networkidle' });\n await page.waitForSelector('[data-pdf-smith-page]', { timeout: 30_000 });\n\n const margin = { top: '0', bottom: '0', left: '0', right: '0' };\n\n const pdfOptions: Parameters<typeof page.pdf>[0] = {\n path: outputPath,\n preferCSSPageSize: true,\n printBackground: true,\n margin,\n };\n\n if (pageNumbers?.enabled) {\n pdfOptions.displayHeaderFooter = true;\n pdfOptions.headerTemplate = '<span></span>';\n pdfOptions.footerTemplate =\n pageNumbers.template ??\n '<div style=\"font-size:10px;text-align:center;width:100%;\"><span class=\"pageNumber\"></span> / <span class=\"totalPages\"></span></div>';\n margin.bottom = '40px';\n }\n\n await page.pdf(pdfOptions);\n } finally {\n await browser.close().catch(() => {});\n await server.close().catch(() => {});\n }\n\n return { outputPath };\n}\n","import type { Plugin } from 'vite';\n\nconst VIRTUAL_PAGES_ID = 'virtual:pdf-smith-pages';\nconst RESOLVED_VIRTUAL_PAGES_ID = `\\0${VIRTUAL_PAGES_ID}`;\n\ninterface PreviewPluginOptions {\n pkgSrcDir: string;\n pagesGlob: string;\n}\n\nexport function pdfSmithPreviewPlugin({ pkgSrcDir, pagesGlob }: PreviewPluginOptions): Plugin {\n return {\n name: 'pdf-smith-preview',\n\n configureServer(server) {\n return () => {\n server.middlewares.use((req, res, next) => {\n if (req.url !== '/' && req.url !== '/index.html') {\n next();\n return;\n }\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <script type=\"module\">\nimport RefreshRuntime from \"/@react-refresh\"\nRefreshRuntime.injectIntoGlobalHook(window)\nwindow.$RefreshReg$ = () => {}\nwindow.$RefreshSig$ = () => (type) => type\nwindow.__vite_plugin_react_preamble_installed__ = true\n</script>\n <script type=\"module\" src=\"/@vite/client\"></script>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>pdf-smith Preview</title>\n <style>\n @media print {\n [data-pdf-smith-nav] { display: none !important; }\n [data-pdf-smith-container] {\n margin-left: 0 !important;\n padding: 0 !important;\n background: none !important;\n }\n [data-pdf-smith-container] > [data-pdf-smith-document] > div {\n margin-bottom: 0 !important;\n }\n [data-pdf-smith-container] > [data-pdf-smith-document] > div > div:first-child {\n display: none !important;\n }\n }\n </style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/@fs/${pkgSrcDir}/preview/entry.tsx\"></script>\n</body>\n</html>`;\n\n res.setHeader('Content-Type', 'text/html');\n res.statusCode = 200;\n res.end(html);\n });\n };\n },\n\n resolveId(id) {\n if (id === VIRTUAL_PAGES_ID) {\n return RESOLVED_VIRTUAL_PAGES_ID;\n }\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_PAGES_ID) {\n return `\nconst modules = import.meta.glob('${pagesGlob}', { eager: true });\n\nexport function getPages() {\n const pages = {};\n for (const [path, mod] of Object.entries(modules)) {\n const name = path\n .replace(/^\\\\/pages\\\\//, '')\n .replace(/\\\\.[^.]+$/, '');\n pages[name] = mod.default;\n }\n return pages;\n}\n`;\n }\n },\n };\n}\n","import type { AddressInfo } from 'node:net';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { PreviewOptions, PreviewServer } from './preview/types';\n\nexport { exportPDF } from './export';\nexport type { ExportOptions, ExportResult } from './export-types';\nexport type { PreviewOptions, PreviewServer } from './preview/types';\n\nexport async function startPreview(options: PreviewOptions): Promise<PreviewServer> {\n const { root, port = 3000, pages = '/pages/**/*.tsx', open = false } = options;\n\n const { createServer } = await import('vite');\n const react = (await import('@vitejs/plugin-react')).default;\n const tailwindcss = (await import('@tailwindcss/vite')).default;\n const { pdfSmithPreviewPlugin } = await import('./preview/preview-plugin');\n\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const pkgRoot = path.resolve(currentDir, '..');\n const pkgSrcDir = path.resolve(pkgRoot, 'src');\n\n const server = await createServer({\n configFile: false,\n appType: 'custom',\n root,\n server: {\n port,\n strictPort: port !== 0,\n open,\n fs: {\n allow: [root, pkgSrcDir, pkgRoot],\n },\n },\n resolve: {\n alias: {\n 'pdf-smith': path.resolve(pkgSrcDir, 'index.ts'),\n },\n dedupe: ['react', 'react-dom'],\n },\n plugins: [react(), tailwindcss(), pdfSmithPreviewPlugin({ pkgSrcDir, pagesGlob: pages })],\n optimizeDeps: {\n include: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime'],\n },\n });\n\n await server.listen();\n\n if (port !== 0) {\n server.printUrls();\n }\n\n const address = server.httpServer?.address() as AddressInfo | null;\n const resolvedPort = address?.port ?? port;\n const url = `http://localhost:${resolvedPort}`;\n\n return {\n close: async () => {\n const httpServer = server.httpServer as { closeAllConnections?: () => void } | null;\n httpServer?.closeAllConnections?.();\n await server.close();\n },\n port: resolvedPort,\n url,\n };\n}\n"],"mappings":"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","names":["path","fs","startPreview","pdfSmithPreviewPlugin","path","import_node_path"]}
|
|
1
|
+
{"version":3,"sources":["../src/export.ts","../src/preview/preview-plugin.ts","../src/server.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { DocumentConfig } from './config';\nimport type { ExportOptions, ExportResult } from './export-types';\n\ninterface DiscoveredDocument {\n slug: string;\n configPath: string | null;\n}\n\nfunction discoverDocuments(root: string): DiscoveredDocument[] {\n const pdfsDir = path.join(root, 'pdfs');\n if (!fs.existsSync(pdfsDir)) return [];\n\n const entries = fs.readdirSync(pdfsDir, { withFileTypes: true });\n const documents: DiscoveredDocument[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const pagesDir = path.join(pdfsDir, entry.name, 'pages');\n if (!fs.existsSync(pagesDir)) continue;\n\n const configPath = path.join(pdfsDir, entry.name, 'config.ts');\n documents.push({\n slug: entry.name,\n configPath: fs.existsSync(configPath) ? configPath : null,\n });\n }\n\n return documents;\n}\n\nexport async function exportPDF(options: ExportOptions): Promise<ExportResult> {\n const { root, document: documentSlug, output } = options;\n const outputDir = path.resolve(root, output ?? 'output');\n\n let documents = discoverDocuments(root);\n\n if (documentSlug) {\n documents = documents.filter((d) => d.slug === documentSlug);\n if (documents.length === 0) {\n throw new Error(\n `Document \"${documentSlug}\" not found. Check that pdfs/${documentSlug}/pages/ exists.`,\n );\n }\n }\n\n if (documents.length === 0) {\n throw new Error('No documents found. Create at least one document in pdfs/<name>/pages/.');\n }\n\n fs.mkdirSync(outputDir, { recursive: true });\n\n let playwright: typeof import('playwright');\n try {\n playwright = await import('playwright');\n } catch {\n throw new Error(\n 'Playwright is required for PDF export. Install it with: npm install -D playwright && npx playwright install chromium',\n );\n }\n\n const { startPreview } = await import('./server');\n const server = await startPreview({ root, port: 0, open: false });\n\n const vite = (\n server as unknown as {\n _vite: { ssrLoadModule: (id: string) => Promise<{ default?: DocumentConfig }> };\n }\n )._vite;\n\n const browser = await playwright.chromium.launch({ headless: true });\n const outputs: ExportResult['outputs'] = [];\n\n try {\n for (const doc of documents) {\n let config: DocumentConfig | undefined;\n if (doc.configPath && vite) {\n try {\n const configModule = await vite.ssrLoadModule(doc.configPath);\n config = configModule.default;\n } catch {\n // Config loading failed, proceed without it\n }\n }\n\n const filename = config?.output ?? `${doc.slug}.pdf`;\n const outputPath = path.resolve(outputDir, filename);\n\n const page = await browser.newPage();\n await page.goto(`${server.url}/${doc.slug}`, { waitUntil: 'networkidle' });\n await page.waitForSelector('[data-pdf-smith-page]', { timeout: 30_000 });\n\n const margin = { top: '0', bottom: '0', left: '0', right: '0' };\n\n const pdfOptions: Parameters<typeof page.pdf>[0] = {\n path: outputPath,\n preferCSSPageSize: true,\n printBackground: true,\n margin,\n };\n\n if (config?.pageNumbers?.enabled) {\n pdfOptions.displayHeaderFooter = true;\n pdfOptions.headerTemplate = '<span></span>';\n pdfOptions.footerTemplate =\n config.pageNumbers.template ??\n '<div style=\"font-size:10px;text-align:center;width:100%;\"><span class=\"pageNumber\"></span> / <span class=\"totalPages\"></span></div>';\n margin.bottom = '40px';\n }\n\n await page.pdf(pdfOptions);\n await page.close();\n\n outputs.push({ document: doc.slug, outputPath });\n }\n } finally {\n await browser.close().catch(() => {});\n await server.close().catch(() => {});\n }\n\n return { outputs };\n}\n","import fs from 'node:fs';\nimport type { AddressInfo } from 'node:net';\nimport path from 'node:path';\nimport type { Plugin } from 'vite';\nimport type { DocumentConfig } from '../config';\n\nconst VIRTUAL_DOCUMENTS_ID = 'virtual:pdf-smith-documents';\nconst RESOLVED_VIRTUAL_DOCUMENTS_ID = `\\0${VIRTUAL_DOCUMENTS_ID}`;\n\ninterface PreviewPluginOptions {\n pkgSrcDir: string;\n}\n\nasync function handleExportRequest(\n server: import('vite').ViteDevServer,\n slug: string,\n res: import('node:http').ServerResponse,\n) {\n const root = server.config.root;\n const pagesDir = path.join(root, 'pdfs', slug, 'pages');\n\n if (!fs.existsSync(pagesDir)) {\n res.statusCode = 404;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: `Document \"${slug}\" not found` }));\n return;\n }\n\n let config: DocumentConfig | undefined;\n const configPath = path.join(root, 'pdfs', slug, 'config.ts');\n if (fs.existsSync(configPath)) {\n try {\n const configModule = await server.ssrLoadModule(configPath);\n config = configModule.default;\n } catch {\n // Config loading failed, proceed without it\n }\n }\n\n let playwright: typeof import('playwright');\n try {\n playwright = await import('playwright');\n } catch {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(\n JSON.stringify({\n error:\n 'Playwright is required for PDF export. Install it with: npm install -D playwright && npx playwright install chromium',\n }),\n );\n return;\n }\n\n let browser: import('playwright').Browser | undefined;\n try {\n const address = server.httpServer?.address() as AddressInfo | null;\n const port = address?.port;\n if (!port) throw new Error('Could not determine server port');\n\n browser = await playwright.chromium.launch({ headless: true });\n const page = await browser.newPage();\n await page.goto(`http://localhost:${port}/${slug}`, { waitUntil: 'networkidle' });\n await page.waitForSelector('[data-pdf-smith-page]', { timeout: 30_000 });\n\n const margin = { top: '0', bottom: '0', left: '0', right: '0' };\n const pdfOptions: Parameters<typeof page.pdf>[0] = {\n preferCSSPageSize: true,\n printBackground: true,\n margin,\n };\n\n if (config?.pageNumbers?.enabled) {\n pdfOptions.displayHeaderFooter = true;\n pdfOptions.headerTemplate = '<span></span>';\n pdfOptions.footerTemplate =\n config.pageNumbers.template ??\n '<div style=\"font-size:10px;text-align:center;width:100%;\"><span class=\"pageNumber\"></span> / <span class=\"totalPages\"></span></div>';\n margin.bottom = '40px';\n }\n\n const buffer = await page.pdf(pdfOptions);\n await page.close();\n\n const filename = config?.output ?? `${slug}.pdf`;\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/pdf');\n res.setHeader('Content-Disposition', `attachment; filename=\"${filename}\"`);\n res.end(buffer);\n } catch (err) {\n if (!res.headersSent) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: err instanceof Error ? err.message : 'PDF export failed' }));\n }\n } finally {\n await browser?.close().catch(() => {});\n }\n}\n\nexport function pdfSmithPreviewPlugin({ pkgSrcDir }: PreviewPluginOptions): Plugin {\n return {\n name: 'pdf-smith-preview',\n\n configureServer(server) {\n // Pre-middleware: Export API runs before Vite internals.\n // Must be a sync function — async middleware returns a Promise that\n // Connect ignores, so the pipeline can advance to the catch-all\n // before the async work finishes.\n server.middlewares.use((req, res, next) => {\n if (req.method !== 'POST') return next();\n const match = req.url?.match(/^\\/api\\/export\\/([^/]+)$/);\n if (!match) return next();\n void handleExportRequest(server, match[1], res);\n });\n\n // Post-middleware: catch-all HTML handler (after Vite internals)\n return () => {\n server.middlewares.use((req, res, next) => {\n const url = req.url ?? '';\n\n // Skip file requests, Vite internals, and node_modules\n if (url.includes('.') || url.startsWith('/@') || url.startsWith('/node_modules/')) {\n next();\n return;\n }\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <script type=\"module\">\nimport RefreshRuntime from \"/@react-refresh\"\nRefreshRuntime.injectIntoGlobalHook(window)\nwindow.$RefreshReg$ = () => {}\nwindow.$RefreshSig$ = () => (type) => type\nwindow.__vite_plugin_react_preamble_installed__ = true\n</script>\n <script type=\"module\" src=\"/@vite/client\"></script>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>pdf-smith Preview</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght,SOFT,WONK@0,9..144,100..900,0..100,0..1&family=Inter:opsz,wght@14..32,100..900&family=JetBrains+Mono:wght@400;500;600&display=swap\" rel=\"stylesheet\">\n <style>\n *, *::before, *::after { box-sizing: border-box; }\n body {\n margin: 0;\n font-family: 'Inter', system-ui, sans-serif;\n -webkit-font-smoothing: antialiased;\n }\n .pdf-smith-search::placeholder { color: #78716C; }\n @media print {\n [data-pdf-smith-nav] { display: none !important; }\n [data-pdf-smith-toolbar] { display: none !important; }\n [data-pdf-smith-minimap] { display: none !important; }\n [data-pdf-smith-container] {\n margin-left: 0 !important;\n padding: 0 !important;\n padding-top: 0 !important;\n background: none !important;\n }\n [data-pdf-smith-container] > div {\n padding: 0 !important;\n gap: 0 !important;\n }\n [data-pdf-smith-document] > div {\n margin-bottom: 0 !important;\n }\n [data-pdf-smith-document] > div > div:first-child {\n display: none !important;\n }\n }\n </style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/@fs/${pkgSrcDir}/preview/entry.tsx\"></script>\n</body>\n</html>`;\n\n res.setHeader('Content-Type', 'text/html');\n res.statusCode = 200;\n res.end(html);\n });\n };\n },\n\n resolveId(id) {\n if (id === VIRTUAL_DOCUMENTS_ID) {\n return RESOLVED_VIRTUAL_DOCUMENTS_ID;\n }\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_DOCUMENTS_ID) {\n return `\nconst pageModules = import.meta.glob('/pdfs/*/pages/**/*.tsx', { eager: true });\nconst configModules = import.meta.glob('/pdfs/*/config.ts', { eager: true });\n\nexport function getDocuments() {\n const documents = {};\n\n for (const [path, mod] of Object.entries(pageModules)) {\n const match = path.match(/^\\\\/pdfs\\\\/([^/]+)\\\\/pages\\\\/(.+)\\\\.[^.]+$/);\n if (!match) continue;\n const [, slug, pageName] = match;\n if (!documents[slug]) {\n documents[slug] = { slug, pages: {}, config: undefined };\n }\n documents[slug].pages[pageName] = mod.default;\n }\n\n for (const [path, mod] of Object.entries(configModules)) {\n const match = path.match(/^\\\\/pdfs\\\\/([^/]+)\\\\/config\\\\.ts$/);\n if (!match) continue;\n const slug = match[1];\n if (documents[slug]) {\n documents[slug].config = mod.default;\n }\n }\n\n return documents;\n}\n\nexport function getDocumentSlugs() {\n return Object.keys(getDocuments());\n}\n`;\n }\n },\n };\n}\n","import type { AddressInfo } from 'node:net';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { PreviewOptions, PreviewServer } from './preview/types';\n\nexport { exportPDF } from './export';\nexport type { ExportOptions, ExportResult } from './export-types';\nexport type { PreviewOptions, PreviewServer } from './preview/types';\n\nexport async function startPreview(options: PreviewOptions): Promise<PreviewServer> {\n const { root, port = 3000, open = false } = options;\n\n const { createServer } = await import('vite');\n const react = (await import('@vitejs/plugin-react')).default;\n const tailwindcss = (await import('@tailwindcss/vite')).default;\n const { pdfSmithPreviewPlugin } = await import('./preview/preview-plugin');\n\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const pkgRoot = path.resolve(currentDir, '..');\n const pkgSrcDir = path.resolve(pkgRoot, 'src');\n\n const server = await createServer({\n configFile: false,\n appType: 'custom',\n root,\n server: {\n port,\n strictPort: port !== 0,\n open,\n fs: {\n allow: [root, pkgSrcDir, pkgRoot],\n },\n },\n resolve: {\n alias: {\n 'pdf-smith': path.resolve(pkgSrcDir, 'index.ts'),\n },\n dedupe: ['react', 'react-dom'],\n },\n plugins: [react(), tailwindcss(), pdfSmithPreviewPlugin({ pkgSrcDir })],\n optimizeDeps: {\n include: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime'],\n },\n });\n\n await server.listen();\n\n if (port !== 0) {\n server.printUrls();\n }\n\n const address = server.httpServer?.address() as AddressInfo | null;\n const resolvedPort = address?.port ?? port;\n const url = `http://localhost:${resolvedPort}`;\n\n const previewServer: PreviewServer = {\n close: async () => {\n const httpServer = server.httpServer as { closeAllConnections?: () => void } | null;\n httpServer?.closeAllConnections?.();\n await server.close();\n },\n port: resolvedPort,\n url,\n };\n\n Object.defineProperty(previewServer, '_vite', {\n value: server,\n enumerable: false,\n });\n\n return previewServer;\n}\n"],"mappings":"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","names":["path","fs","startPreview","path","fs","import_node_fs","import_node_path","pdfSmithPreviewPlugin","path","import_node_path"]}
|
package/dist/server.d.cts
CHANGED
|
@@ -3,7 +3,6 @@ interface PreviewOptions {
|
|
|
3
3
|
root: string;
|
|
4
4
|
/** Dev server port (default: 3000) */
|
|
5
5
|
port?: number;
|
|
6
|
-
pages?: string;
|
|
7
6
|
/** Auto-open browser (default: false) */
|
|
8
7
|
open?: boolean;
|
|
9
8
|
}
|
|
@@ -15,15 +14,14 @@ interface PreviewServer {
|
|
|
15
14
|
|
|
16
15
|
interface ExportOptions {
|
|
17
16
|
root: string;
|
|
17
|
+
document?: string;
|
|
18
18
|
output?: string;
|
|
19
|
-
pageNumbers?: {
|
|
20
|
-
enabled: boolean;
|
|
21
|
-
template?: string;
|
|
22
|
-
};
|
|
23
|
-
pages?: string;
|
|
24
19
|
}
|
|
25
20
|
interface ExportResult {
|
|
26
|
-
|
|
21
|
+
outputs: Array<{
|
|
22
|
+
document: string;
|
|
23
|
+
outputPath: string;
|
|
24
|
+
}>;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
declare function exportPDF(options: ExportOptions): Promise<ExportResult>;
|
package/dist/server.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ interface PreviewOptions {
|
|
|
3
3
|
root: string;
|
|
4
4
|
/** Dev server port (default: 3000) */
|
|
5
5
|
port?: number;
|
|
6
|
-
pages?: string;
|
|
7
6
|
/** Auto-open browser (default: false) */
|
|
8
7
|
open?: boolean;
|
|
9
8
|
}
|
|
@@ -15,15 +14,14 @@ interface PreviewServer {
|
|
|
15
14
|
|
|
16
15
|
interface ExportOptions {
|
|
17
16
|
root: string;
|
|
17
|
+
document?: string;
|
|
18
18
|
output?: string;
|
|
19
|
-
pageNumbers?: {
|
|
20
|
-
enabled: boolean;
|
|
21
|
-
template?: string;
|
|
22
|
-
};
|
|
23
|
-
pages?: string;
|
|
24
19
|
}
|
|
25
20
|
interface ExportResult {
|
|
26
|
-
|
|
21
|
+
outputs: Array<{
|
|
22
|
+
document: string;
|
|
23
|
+
outputPath: string;
|
|
24
|
+
}>;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
declare function exportPDF(options: ExportOptions): Promise<ExportResult>;
|