@binary1702/site-packet 0.1.1 → 0.1.2

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/bin/cli.js CHANGED
@@ -17,6 +17,7 @@ Options:
17
17
  --output, -o <dir> Output directory (default: ./site-packet)
18
18
  --limit, -l <n> Maximum pages to capture (default: 100)
19
19
  --password, -p <pass> Site password (for password-protected sites)
20
+ --screenshots, -s Also capture full-page screenshots (PNG)
20
21
  --help, -h Show this help message
21
22
 
22
23
  Examples:
@@ -33,6 +34,7 @@ let url = null;
33
34
  let outputDir = './site-packet';
34
35
  let limit = 100;
35
36
  let password = null;
37
+ let screenshots = false;
36
38
 
37
39
  for (let i = 0; i < args.length; i++) {
38
40
  const arg = args[i];
@@ -47,6 +49,8 @@ for (let i = 0; i < args.length; i++) {
47
49
  }
48
50
  } else if (arg === '--password' || arg === '-p') {
49
51
  password = args[++i];
52
+ } else if (arg === '--screenshots' || arg === '-s') {
53
+ screenshots = true;
50
54
  } else if (!arg.startsWith('-')) {
51
55
  url = arg;
52
56
  }
@@ -68,7 +72,7 @@ try {
68
72
 
69
73
  // Run
70
74
  try {
71
- await createPacket(url, { outputDir, limit, password });
75
+ await createPacket(url, { outputDir, limit, password, screenshots });
72
76
  } catch (error) {
73
77
  console.error(`\nFatal error: ${error.message}`);
74
78
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@binary1702/site-packet",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Turn a public website into a printable website review packet",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -11,7 +11,7 @@ import { ensureOutputDirs, writeCapture, writeIndex } from './output.js';
11
11
  * Create a website review packet
12
12
  */
13
13
  export async function createPacket(seedUrl, options = {}) {
14
- const { outputDir = './site-packet', limit = 100, password = null } = options;
14
+ const { outputDir = './site-packet', limit = 100, password = null, screenshots = false } = options;
15
15
 
16
16
  console.log('\nsite-packet');
17
17
  console.log(`Crawling ${seedUrl}...`);
@@ -24,7 +24,7 @@ export async function createPacket(seedUrl, options = {}) {
24
24
  }
25
25
 
26
26
  // Setup
27
- await ensureOutputDirs(outputDir);
27
+ await ensureOutputDirs(outputDir, { screenshots });
28
28
  const browser = await createBrowser();
29
29
 
30
30
  // Create a shared context (for cookie persistence across pages)
@@ -100,7 +100,9 @@ export async function createPacket(seedUrl, options = {}) {
100
100
  if (authSessionData) {
101
101
  captureOptions.sessionData = authSessionData;
102
102
  }
103
- const { title, screenshot, pdf, finalUrl } = await capturePage(page, url, captureOptions);
103
+ const capture = await capturePage(page, url, { ...captureOptions, screenshots });
104
+ const { title, pdf, finalUrl } = capture;
105
+ const screenshot = capture.screenshot;
104
106
 
105
107
  // After first page, lock to the resolved origin
106
108
  if (!effectiveOrigin) {
@@ -126,8 +128,8 @@ export async function createPacket(seedUrl, options = {}) {
126
128
  const { pdfPath, screenshotPath } = await writeCapture(
127
129
  outputDir,
128
130
  filename,
129
- screenshot,
130
- pdf
131
+ pdf,
132
+ screenshot
131
133
  );
132
134
 
133
135
  results.push({
package/src/output.js CHANGED
@@ -8,27 +8,35 @@ import { join } from 'node:path';
8
8
  /**
9
9
  * Ensure output directories exist
10
10
  */
11
- export async function ensureOutputDirs(outputDir) {
11
+ export async function ensureOutputDirs(outputDir, options = {}) {
12
+ const { screenshots = false } = options;
12
13
  await mkdir(join(outputDir, 'pdf'), { recursive: true });
13
- await mkdir(join(outputDir, 'screenshots'), { recursive: true });
14
+ if (screenshots) {
15
+ await mkdir(join(outputDir, 'screenshots'), { recursive: true });
16
+ }
14
17
  }
15
18
 
16
19
  /**
17
- * Write screenshot and PDF files
20
+ * Write PDF and optionally screenshot files
18
21
  * Returns { pdfPath, screenshotPath }
19
22
  */
20
- export async function writeCapture(outputDir, filename, screenshot, pdf) {
23
+ export async function writeCapture(outputDir, filename, pdf, screenshot = null) {
21
24
  const pdfPath = join(outputDir, 'pdf', `${filename}.pdf`);
22
- const screenshotPath = join(outputDir, 'screenshots', `${filename}.png`);
23
25
 
24
- await Promise.all([
25
- writeFile(pdfPath, pdf),
26
- writeFile(screenshotPath, screenshot),
27
- ]);
26
+ const writes = [writeFile(pdfPath, pdf)];
27
+
28
+ let screenshotPath = null;
29
+ if (screenshot) {
30
+ const screenshotFullPath = join(outputDir, 'screenshots', `${filename}.png`);
31
+ writes.push(writeFile(screenshotFullPath, screenshot));
32
+ screenshotPath = `screenshots/${filename}.png`;
33
+ }
34
+
35
+ await Promise.all(writes);
28
36
 
29
37
  return {
30
38
  pdfPath: `pdf/${filename}.pdf`,
31
- screenshotPath: `screenshots/${filename}.png`,
39
+ screenshotPath,
32
40
  };
33
41
  }
34
42
 
@@ -146,7 +154,7 @@ export async function writeIndex(outputDir, pages, metadata) {
146
154
  <td class="url">${escapeHtml(new URL(p.url).pathname)}</td>
147
155
  <td class="links">
148
156
  <a href="${escapeHtml(p.pdfPath)}" class="link-pdf">PDF</a>
149
- <a href="${escapeHtml(p.screenshotPath)}" class="link-screenshot">PNG</a>
157
+ ${p.screenshotPath ? `<a href="${escapeHtml(p.screenshotPath)}" class="link-screenshot">PNG</a>` : ''}
150
158
  </td>
151
159
  </tr>
152
160
  `).join('')}
package/src/renderer.js CHANGED
@@ -123,7 +123,7 @@ export async function enterPassword(page, url, password) {
123
123
  }
124
124
 
125
125
  /**
126
- * Navigate to a URL and capture screenshot + PDF
126
+ * Navigate to a URL and capture PDF (and optionally screenshot)
127
127
  * Returns { title, screenshot, pdf, finalUrl } buffers or throws on failure
128
128
  *
129
129
  * @param {object} options
@@ -131,9 +131,10 @@ export async function enterPassword(page, url, password) {
131
131
  * @param {string} options.allowedOrigin - If provided, only allow redirects within this origin
132
132
  * @param {boolean} options.skipNavigation - If true, skip navigation (page already loaded)
133
133
  * @param {object} options.sessionData - sessionStorage data to inject before navigation
134
+ * @param {boolean} options.screenshots - If true, also capture full-page screenshot
134
135
  */
135
136
  export async function capturePage(page, url, options = {}) {
136
- const { timeout = 30000, allowedOrigin = null, skipNavigation = false, sessionData = null } = options;
137
+ const { timeout = 30000, allowedOrigin = null, skipNavigation = false, sessionData = null, screenshots = false } = options;
137
138
 
138
139
  if (!skipNavigation) {
139
140
  // If we have sessionData, we need to inject it after navigating to the domain
@@ -181,11 +182,14 @@ export async function capturePage(page, url, options = {}) {
181
182
  // Small delay for final renders
182
183
  await page.waitForTimeout(500);
183
184
 
184
- // Full-page screenshot
185
- const screenshot = await page.screenshot({
186
- fullPage: true,
187
- type: 'png',
188
- });
185
+ // Full-page screenshot (only if requested)
186
+ let screenshot = null;
187
+ if (screenshots) {
188
+ screenshot = await page.screenshot({
189
+ fullPage: true,
190
+ type: 'png',
191
+ });
192
+ }
189
193
 
190
194
  // Letter-size PDF with backgrounds
191
195
  const pdf = await page.pdf({