pdf-smith 0.2.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.
@@ -0,0 +1,199 @@
1
+ // src/preview/preview-plugin.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ var VIRTUAL_DOCUMENTS_ID = "virtual:pdf-smith-documents";
5
+ var RESOLVED_VIRTUAL_DOCUMENTS_ID = `\0${VIRTUAL_DOCUMENTS_ID}`;
6
+ async function handleExportRequest(server, slug, res) {
7
+ const root = server.config.root;
8
+ const pagesDir = path.join(root, "pdfs", slug, "pages");
9
+ if (!fs.existsSync(pagesDir)) {
10
+ res.statusCode = 404;
11
+ res.setHeader("Content-Type", "application/json");
12
+ res.end(JSON.stringify({ error: `Document "${slug}" not found` }));
13
+ return;
14
+ }
15
+ let config;
16
+ const configPath = path.join(root, "pdfs", slug, "config.ts");
17
+ if (fs.existsSync(configPath)) {
18
+ try {
19
+ const configModule = await server.ssrLoadModule(configPath);
20
+ config = configModule.default;
21
+ } catch {
22
+ }
23
+ }
24
+ let playwright;
25
+ try {
26
+ playwright = await import("playwright");
27
+ } catch {
28
+ res.statusCode = 500;
29
+ res.setHeader("Content-Type", "application/json");
30
+ res.end(
31
+ JSON.stringify({
32
+ error: "Playwright is required for PDF export. Install it with: npm install -D playwright && npx playwright install chromium"
33
+ })
34
+ );
35
+ return;
36
+ }
37
+ let browser;
38
+ try {
39
+ const address = server.httpServer?.address();
40
+ const port = address?.port;
41
+ if (!port) throw new Error("Could not determine server port");
42
+ browser = await playwright.chromium.launch({ headless: true });
43
+ const page = await browser.newPage();
44
+ await page.goto(`http://localhost:${port}/${slug}`, { waitUntil: "networkidle" });
45
+ await page.waitForSelector("[data-pdf-smith-page]", { timeout: 3e4 });
46
+ const margin = { top: "0", bottom: "0", left: "0", right: "0" };
47
+ const pdfOptions = {
48
+ preferCSSPageSize: true,
49
+ printBackground: true,
50
+ margin
51
+ };
52
+ if (config?.pageNumbers?.enabled) {
53
+ pdfOptions.displayHeaderFooter = true;
54
+ pdfOptions.headerTemplate = "<span></span>";
55
+ pdfOptions.footerTemplate = config.pageNumbers.template ?? '<div style="font-size:10px;text-align:center;width:100%;"><span class="pageNumber"></span> / <span class="totalPages"></span></div>';
56
+ margin.bottom = "40px";
57
+ }
58
+ const buffer = await page.pdf(pdfOptions);
59
+ await page.close();
60
+ const filename = config?.output ?? `${slug}.pdf`;
61
+ res.statusCode = 200;
62
+ res.setHeader("Content-Type", "application/pdf");
63
+ res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
64
+ res.end(buffer);
65
+ } catch (err) {
66
+ if (!res.headersSent) {
67
+ res.statusCode = 500;
68
+ res.setHeader("Content-Type", "application/json");
69
+ res.end(JSON.stringify({ error: err instanceof Error ? err.message : "PDF export failed" }));
70
+ }
71
+ } finally {
72
+ await browser?.close().catch(() => {
73
+ });
74
+ }
75
+ }
76
+ function pdfSmithPreviewPlugin({ pkgSrcDir }) {
77
+ return {
78
+ name: "pdf-smith-preview",
79
+ configureServer(server) {
80
+ server.middlewares.use((req, res, next) => {
81
+ if (req.method !== "POST") return next();
82
+ const match = req.url?.match(/^\/api\/export\/([^/]+)$/);
83
+ if (!match) return next();
84
+ void handleExportRequest(server, match[1], res);
85
+ });
86
+ return () => {
87
+ server.middlewares.use((req, res, next) => {
88
+ const url = req.url ?? "";
89
+ if (url.includes(".") || url.startsWith("/@") || url.startsWith("/node_modules/")) {
90
+ next();
91
+ return;
92
+ }
93
+ const html = `<!DOCTYPE html>
94
+ <html lang="en">
95
+ <head>
96
+ <script type="module">
97
+ import RefreshRuntime from "/@react-refresh"
98
+ RefreshRuntime.injectIntoGlobalHook(window)
99
+ window.$RefreshReg$ = () => {}
100
+ window.$RefreshSig$ = () => (type) => type
101
+ window.__vite_plugin_react_preamble_installed__ = true
102
+ </script>
103
+ <script type="module" src="/@vite/client"></script>
104
+ <meta charset="UTF-8" />
105
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
106
+ <title>pdf-smith Preview</title>
107
+ <link rel="preconnect" href="https://fonts.googleapis.com">
108
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
109
+ <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">
110
+ <style>
111
+ *, *::before, *::after { box-sizing: border-box; }
112
+ body {
113
+ margin: 0;
114
+ font-family: 'Inter', system-ui, sans-serif;
115
+ -webkit-font-smoothing: antialiased;
116
+ }
117
+ .pdf-smith-search::placeholder { color: #78716C; }
118
+ @media print {
119
+ [data-pdf-smith-nav] { display: none !important; }
120
+ [data-pdf-smith-toolbar] { display: none !important; }
121
+ [data-pdf-smith-minimap] { display: none !important; }
122
+ [data-pdf-smith-container] {
123
+ margin-left: 0 !important;
124
+ padding: 0 !important;
125
+ padding-top: 0 !important;
126
+ background: none !important;
127
+ }
128
+ [data-pdf-smith-container] > div {
129
+ padding: 0 !important;
130
+ gap: 0 !important;
131
+ }
132
+ [data-pdf-smith-document] > div {
133
+ margin-bottom: 0 !important;
134
+ }
135
+ [data-pdf-smith-document] > div > div:first-child {
136
+ display: none !important;
137
+ }
138
+ }
139
+ </style>
140
+ </head>
141
+ <body>
142
+ <div id="root"></div>
143
+ <script type="module" src="/@fs/${pkgSrcDir}/preview/entry.tsx"></script>
144
+ </body>
145
+ </html>`;
146
+ res.setHeader("Content-Type", "text/html");
147
+ res.statusCode = 200;
148
+ res.end(html);
149
+ });
150
+ };
151
+ },
152
+ resolveId(id) {
153
+ if (id === VIRTUAL_DOCUMENTS_ID) {
154
+ return RESOLVED_VIRTUAL_DOCUMENTS_ID;
155
+ }
156
+ },
157
+ load(id) {
158
+ if (id === RESOLVED_VIRTUAL_DOCUMENTS_ID) {
159
+ return `
160
+ const pageModules = import.meta.glob('/pdfs/*/pages/**/*.tsx', { eager: true });
161
+ const configModules = import.meta.glob('/pdfs/*/config.ts', { eager: true });
162
+
163
+ export function getDocuments() {
164
+ const documents = {};
165
+
166
+ for (const [path, mod] of Object.entries(pageModules)) {
167
+ const match = path.match(/^\\/pdfs\\/([^/]+)\\/pages\\/(.+)\\.[^.]+$/);
168
+ if (!match) continue;
169
+ const [, slug, pageName] = match;
170
+ if (!documents[slug]) {
171
+ documents[slug] = { slug, pages: {}, config: undefined };
172
+ }
173
+ documents[slug].pages[pageName] = mod.default;
174
+ }
175
+
176
+ for (const [path, mod] of Object.entries(configModules)) {
177
+ const match = path.match(/^\\/pdfs\\/([^/]+)\\/config\\.ts$/);
178
+ if (!match) continue;
179
+ const slug = match[1];
180
+ if (documents[slug]) {
181
+ documents[slug].config = mod.default;
182
+ }
183
+ }
184
+
185
+ return documents;
186
+ }
187
+
188
+ export function getDocumentSlugs() {
189
+ return Object.keys(getDocuments());
190
+ }
191
+ `;
192
+ }
193
+ }
194
+ };
195
+ }
196
+ export {
197
+ pdfSmithPreviewPlugin
198
+ };
199
+ //# sourceMappingURL=preview-plugin-26BUIGCE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/preview/preview-plugin.ts"],"sourcesContent":["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"],"mappings":"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","names":[]}
package/dist/server.cjs CHANGED
@@ -131,10 +131,86 @@ var preview_plugin_exports = {};
131
131
  __export(preview_plugin_exports, {
132
132
  pdfSmithPreviewPlugin: () => pdfSmithPreviewPlugin
133
133
  });
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
+ }
134
204
  function pdfSmithPreviewPlugin({ pkgSrcDir }) {
135
205
  return {
136
206
  name: "pdf-smith-preview",
137
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
+ });
138
214
  return () => {
139
215
  server.middlewares.use((req, res, next) => {
140
216
  const url = req.url ?? "";
@@ -156,18 +232,35 @@ window.__vite_plugin_react_preamble_installed__ = true
156
232
  <meta charset="UTF-8" />
157
233
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
158
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">
159
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; }
160
246
  @media print {
161
247
  [data-pdf-smith-nav] { display: none !important; }
248
+ [data-pdf-smith-toolbar] { display: none !important; }
249
+ [data-pdf-smith-minimap] { display: none !important; }
162
250
  [data-pdf-smith-container] {
163
251
  margin-left: 0 !important;
164
252
  padding: 0 !important;
253
+ padding-top: 0 !important;
165
254
  background: none !important;
166
255
  }
167
- [data-pdf-smith-container] > [data-pdf-smith-document] > div {
256
+ [data-pdf-smith-container] > div {
257
+ padding: 0 !important;
258
+ gap: 0 !important;
259
+ }
260
+ [data-pdf-smith-document] > div {
168
261
  margin-bottom: 0 !important;
169
262
  }
170
- [data-pdf-smith-container] > [data-pdf-smith-document] > div > div:first-child {
263
+ [data-pdf-smith-document] > div > div:first-child {
171
264
  display: none !important;
172
265
  }
173
266
  }
@@ -228,10 +321,12 @@ export function getDocumentSlugs() {
228
321
  }
229
322
  };
230
323
  }
231
- var VIRTUAL_DOCUMENTS_ID, RESOLVED_VIRTUAL_DOCUMENTS_ID;
324
+ var import_node_fs2, import_node_path2, VIRTUAL_DOCUMENTS_ID, RESOLVED_VIRTUAL_DOCUMENTS_ID;
232
325
  var init_preview_plugin = __esm({
233
326
  "src/preview/preview-plugin.ts"() {
234
327
  "use strict";
328
+ import_node_fs2 = __toESM(require("fs"), 1);
329
+ import_node_path2 = __toESM(require("path"), 1);
235
330
  VIRTUAL_DOCUMENTS_ID = "virtual:pdf-smith-documents";
236
331
  RESOLVED_VIRTUAL_DOCUMENTS_ID = `\0${VIRTUAL_DOCUMENTS_ID}`;
237
332
  }
@@ -250,9 +345,9 @@ async function startPreview(options) {
250
345
  const react = (await import("@vitejs/plugin-react")).default;
251
346
  const tailwindcss = (await import("@tailwindcss/vite")).default;
252
347
  const { pdfSmithPreviewPlugin: pdfSmithPreviewPlugin2 } = await Promise.resolve().then(() => (init_preview_plugin(), preview_plugin_exports));
253
- const currentDir = import_node_path2.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
254
- const pkgRoot = import_node_path2.default.resolve(currentDir, "..");
255
- const pkgSrcDir = import_node_path2.default.resolve(pkgRoot, "src");
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");
256
351
  const server = await createServer({
257
352
  configFile: false,
258
353
  appType: "custom",
@@ -267,7 +362,7 @@ async function startPreview(options) {
267
362
  },
268
363
  resolve: {
269
364
  alias: {
270
- "pdf-smith": import_node_path2.default.resolve(pkgSrcDir, "index.ts")
365
+ "pdf-smith": import_node_path3.default.resolve(pkgSrcDir, "index.ts")
271
366
  },
272
367
  dedupe: ["react", "react-dom"]
273
368
  },
@@ -298,10 +393,10 @@ async function startPreview(options) {
298
393
  });
299
394
  return previewServer;
300
395
  }
301
- var import_node_path2, import_node_url, import_meta;
396
+ var import_node_path3, import_node_url, import_meta;
302
397
  var init_server = __esm({
303
398
  "src/server.ts"() {
304
- import_node_path2 = __toESM(require("path"), 1);
399
+ import_node_path3 = __toESM(require("path"), 1);
305
400
  import_node_url = require("url");
306
401
  init_export();
307
402
  import_meta = {};
@@ -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 { 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 type { Plugin } from 'vite';\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\nexport function pdfSmithPreviewPlugin({ pkgSrcDir }: PreviewPluginOptions): Plugin {\n return {\n name: 'pdf-smith-preview',\n\n configureServer(server) {\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 <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_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","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.js CHANGED
@@ -98,7 +98,7 @@ async function startPreview(options) {
98
98
  const { createServer } = await import("vite");
99
99
  const react = (await import("@vitejs/plugin-react")).default;
100
100
  const tailwindcss = (await import("@tailwindcss/vite")).default;
101
- const { pdfSmithPreviewPlugin } = await import("./preview-plugin-QDLEMAEE.js");
101
+ const { pdfSmithPreviewPlugin } = await import("./preview-plugin-26BUIGCE.js");
102
102
  const currentDir = path2.dirname(fileURLToPath(import.meta.url));
103
103
  const pkgRoot = path2.resolve(currentDir, "..");
104
104
  const pkgSrcDir = path2.resolve(pkgRoot, "src");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-smith",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Build beautiful PDFs with React components and Tailwind CSS",
5
5
  "author": "Kareem Elbahrawy",
6
6
  "license": "MIT",