11import puppeteer from 'puppeteer-core' ;
22import chromium from 'chrome-aws-lambda' ;
33import middleware from './_common/middleware.js' ;
4+ import { exec } from 'child_process' ;
5+ import { promises as fs } from 'fs' ;
6+ import path from 'path' ;
7+ import pkg from 'uuid' ;
8+ const { v4 : uuidv4 } = pkg ;
49
5- const screenshotHandler = async ( targetUrl ) => {
10+ // Helper function for direct chromium screenshot as fallback
11+ const directChromiumScreenshot = async ( url ) => {
12+ console . log ( `[DIRECT-SCREENSHOT] Starting direct screenshot process for URL: ${ url } ` ) ;
13+
14+ // Create a tmp filename
15+ const tmpDir = '/tmp' ;
16+ const uuid = uuidv4 ( ) ;
17+ const screenshotPath = path . join ( tmpDir , `screenshot-${ uuid } .png` ) ;
18+
19+ console . log ( `[DIRECT-SCREENSHOT] Will save screenshot to: ${ screenshotPath } ` ) ;
20+
21+ return new Promise ( ( resolve , reject ) => {
22+ const chromePath = process . env . CHROME_PATH || '/usr/bin/chromium' ;
23+ const command = `${ chromePath } --headless --disable-gpu --no-sandbox --screenshot=${ screenshotPath } "${ url } "` ;
24+
25+ console . log ( `[DIRECT-SCREENSHOT] Executing command: ${ command } ` ) ;
26+
27+ exec ( command , async ( error , stdout , stderr ) => {
28+ if ( error ) {
29+ console . error ( `[DIRECT-SCREENSHOT] Error executing Chromium: ${ error . message } ` ) ;
30+ return reject ( error ) ;
31+ }
32+
33+ try {
34+ // Read screenshot
35+ const screenshotData = await fs . readFile ( screenshotPath ) ;
36+ console . log ( `[DIRECT-SCREENSHOT] Read ${ screenshotData . length } bytes from screenshot file` ) ;
37+
38+ // Convert base64
39+ const base64Data = screenshotData . toString ( 'base64' ) ;
40+
41+ // Clean
42+ await fs . unlink ( screenshotPath ) . catch ( err =>
43+ console . warn ( `[DIRECT-SCREENSHOT] Failed to delete temp file: ${ err . message } ` )
44+ ) ;
45+
46+ resolve ( base64Data ) ;
47+ } catch ( readError ) {
48+ console . error ( `[DIRECT-SCREENSHOT] Error reading screenshot: ${ readError . message } ` ) ;
49+ reject ( readError ) ;
50+ }
51+ } ) ;
52+ } ) ;
53+ } ;
654
55+ const screenshotHandler = async ( targetUrl ) => {
56+ console . log ( `[SCREENSHOT] Request received for URL: ${ targetUrl } ` ) ;
57+
758 if ( ! targetUrl ) {
59+ console . error ( '[SCREENSHOT] URL is missing from queryStringParameters' ) ;
860 throw new Error ( 'URL is missing from queryStringParameters' ) ;
961 }
10-
62+
1163 if ( ! targetUrl . startsWith ( 'http://' ) && ! targetUrl . startsWith ( 'https://' ) ) {
1264 targetUrl = 'http://' + targetUrl ;
1365 }
14-
66+
1567 try {
1668 new URL ( targetUrl ) ;
1769 } catch ( error ) {
70+ console . error ( `[SCREENSHOT] URL provided is invalid: ${ targetUrl } ` ) ;
1871 throw new Error ( 'URL provided is invalid' ) ;
1972 }
2073
74+ // First try direct Chromium
75+ try {
76+ console . log ( `[SCREENSHOT] Using direct Chromium method for URL: ${ targetUrl } ` ) ;
77+ const base64Screenshot = await directChromiumScreenshot ( targetUrl ) ;
78+ console . log ( `[SCREENSHOT] Direct screenshot successful` ) ;
79+ return { image : base64Screenshot } ;
80+ } catch ( directError ) {
81+ console . error ( `[SCREENSHOT] Direct screenshot method failed: ${ directError . message } ` ) ;
82+ console . log ( `[SCREENSHOT] Falling back to puppeteer method...` ) ;
83+ }
84+
85+ // fall back puppeteer
2186 let browser = null ;
2287 try {
23- browser = await puppeteer . launch ( {
88+ console . log ( `[SCREENSHOT] Launching puppeteer browser` ) ;
89+ browser = await puppeteer . launch ( {
2490 args : [ ...chromium . args , '--no-sandbox' ] , // Add --no-sandbox flag
2591 defaultViewport : { width : 800 , height : 600 } ,
26- executablePath : process . env . CHROME_PATH || await chromium . executablePath ,
27- headless : chromium . headless ,
92+ executablePath : process . env . CHROME_PATH || '/usr/bin/ chromium' ,
93+ headless : true ,
2894 ignoreHTTPSErrors : true ,
2995 ignoreDefaultArgs : [ '--disable-extensions' ] ,
3096 } ) ;
31-
97+
98+ console . log ( `[SCREENSHOT] Creating new page` ) ;
3299 let page = await browser . newPage ( ) ;
33-
100+
101+ console . log ( `[SCREENSHOT] Setting page preferences` ) ;
34102 await page . emulateMediaFeatures ( [ { name : 'prefers-color-scheme' , value : 'dark' } ] ) ;
35103 page . setDefaultNavigationTimeout ( 8000 ) ;
104+
105+ console . log ( `[SCREENSHOT] Navigating to URL: ${ targetUrl } ` ) ;
36106 await page . goto ( targetUrl , { waitUntil : 'domcontentloaded' } ) ;
37-
107+
108+ console . log ( `[SCREENSHOT] Checking if body element exists` ) ;
38109 await page . evaluate ( ( ) => {
39110 const selector = 'body' ;
40111 return new Promise ( ( resolve , reject ) => {
@@ -45,14 +116,21 @@ const screenshotHandler = async (targetUrl) => {
45116 resolve ( ) ;
46117 } ) ;
47118 } ) ;
48-
119+
120+ console . log ( `[SCREENSHOT] Taking screenshot` ) ;
49121 const screenshotBuffer = await page . screenshot ( ) ;
122+
123+ console . log ( `[SCREENSHOT] Converting screenshot to base64` ) ;
50124 const base64Screenshot = screenshotBuffer . toString ( 'base64' ) ;
51-
125+
126+ console . log ( `[SCREENSHOT] Screenshot complete, returning image` ) ;
52127 return { image : base64Screenshot } ;
53-
128+ } catch ( error ) {
129+ console . error ( `[SCREENSHOT] Puppeteer screenshot failed: ${ error . message } ` ) ;
130+ throw error ;
54131 } finally {
55132 if ( browser !== null ) {
133+ console . log ( `[SCREENSHOT] Closing browser` ) ;
56134 await browser . close ( ) ;
57135 }
58136 }
0 commit comments