@@ -39,67 +39,82 @@ const screenshotSchema = z.object({
3939 headers : z . record ( z . string ( ) , z . any ( ) ) . optional ( ) ,
4040 sleep : z . number ( ) . min ( 0 ) . max ( 60000 ) . default ( 3000 ) ,
4141 // Viewport options
42- viewport : z . object ( {
43- width : z . number ( ) . min ( 1 ) . max ( 3840 ) . default ( 1280 ) ,
44- height : z . number ( ) . min ( 1 ) . max ( 2160 ) . default ( 720 ) ,
45- } ) . optional ( ) ,
42+ viewport : z
43+ . object ( {
44+ width : z . number ( ) . min ( 1 ) . max ( 3840 ) . default ( 1280 ) ,
45+ height : z . number ( ) . min ( 1 ) . max ( 2160 ) . default ( 720 ) ,
46+ } )
47+ . optional ( ) ,
4648 // Screenshot options
4749 format : z . enum ( [ "png" , "jpeg" , "webp" ] ) . default ( "png" ) ,
4850 quality : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 90 ) ,
4951 fullPage : z . boolean ( ) . default ( false ) ,
50- clip : z . object ( {
51- x : z . number ( ) . min ( 0 ) ,
52- y : z . number ( ) . min ( 0 ) ,
53- width : z . number ( ) . min ( 1 ) ,
54- height : z . number ( ) . min ( 1 ) ,
55- } ) . optional ( ) ,
52+ clip : z
53+ . object ( {
54+ x : z . number ( ) . min ( 0 ) ,
55+ y : z . number ( ) . min ( 0 ) ,
56+ width : z . number ( ) . min ( 1 ) ,
57+ height : z . number ( ) . min ( 1 ) ,
58+ } )
59+ . optional ( ) ,
5660 // Browser context options
5761 userAgent : z . string ( ) . optional ( ) ,
5862 locale : z . string ( ) . optional ( ) ,
59- timezoneId : z . string ( ) . regex (
60- / ^ ( A f r i c a | A m e r i c a | A n t a r c t i c a | A r c t i c | A s i a | A t l a n t i c | A u s t r a l i a | E u r o p e | I n d i a n | P a c i f i c | U T C ) \/ [ A - Z a - z _ ] + $ / ,
61- "Must be a valid IANA timezone identifier (e.g., 'America/New_York', 'Europe/London', 'Asia/Tokyo')"
62- ) . optional ( ) ,
63- geolocation : z . object ( {
64- latitude : z . number ( ) . min ( - 90 ) . max ( 90 ) ,
65- longitude : z . number ( ) . min ( - 180 ) . max ( 180 ) ,
66- accuracy : z . number ( ) . min ( 0 ) . optional ( ) ,
67- } ) . optional ( ) ,
68- permissions : z . array ( z . enum ( [
69- "geolocation" ,
70- "camera" ,
71- "microphone" ,
72- "notifications" ,
73- "clipboard-read" ,
74- "clipboard-write" ,
75- "payment-handler" ,
76- "midi" ,
77- "usb" ,
78- "serial" ,
79- "bluetooth" ,
80- "persistent-storage" ,
81- "accelerometer" ,
82- "gyroscope" ,
83- "magnetometer" ,
84- "ambient-light-sensor" ,
85- "background-sync" ,
86- "background-fetch" ,
87- "idle-detection" ,
88- "periodic-background-sync" ,
89- "push" ,
90- "speaker-selection" ,
91- "storage-access" ,
92- "top-level-storage-access" ,
93- "window-management" ,
94- "local-fonts" ,
95- "display-capture" ,
96- "nfc" ,
97- "screen-wake-lock" ,
98- "web-share" ,
99- "xr-spatial-tracking"
100- ] ) ) . optional ( ) ,
63+ timezoneId : z
64+ . string ( )
65+ . regex (
66+ / ^ ( A f r i c a | A m e r i c a | A n t a r c t i c a | A r c t i c | A s i a | A t l a n t i c | A u s t r a l i a | E u r o p e | I n d i a n | P a c i f i c | U T C ) \/ [ A - Z a - z _ ] + $ / ,
67+ "Must be a valid IANA timezone identifier (e.g., 'America/New_York', 'Europe/London', 'Asia/Tokyo')" ,
68+ )
69+ . optional ( ) ,
70+ geolocation : z
71+ . object ( {
72+ latitude : z . number ( ) . min ( - 90 ) . max ( 90 ) ,
73+ longitude : z . number ( ) . min ( - 180 ) . max ( 180 ) ,
74+ accuracy : z . number ( ) . min ( 0 ) . optional ( ) ,
75+ } )
76+ . optional ( ) ,
77+ permissions : z
78+ . array (
79+ z . enum ( [
80+ "geolocation" ,
81+ "camera" ,
82+ "microphone" ,
83+ "notifications" ,
84+ "clipboard-read" ,
85+ "clipboard-write" ,
86+ "payment-handler" ,
87+ "midi" ,
88+ "usb" ,
89+ "serial" ,
90+ "bluetooth" ,
91+ "persistent-storage" ,
92+ "accelerometer" ,
93+ "gyroscope" ,
94+ "magnetometer" ,
95+ "ambient-light-sensor" ,
96+ "background-sync" ,
97+ "background-fetch" ,
98+ "idle-detection" ,
99+ "periodic-background-sync" ,
100+ "push" ,
101+ "speaker-selection" ,
102+ "storage-access" ,
103+ "top-level-storage-access" ,
104+ "window-management" ,
105+ "local-fonts" ,
106+ "display-capture" ,
107+ "nfc" ,
108+ "screen-wake-lock" ,
109+ "web-share" ,
110+ "xr-spatial-tracking" ,
111+ ] ) ,
112+ )
113+ . optional ( ) ,
101114 // Navigation options
102- waitUntil : z . enum ( [ "load" , "domcontentloaded" , "networkidle" , "commit" ] ) . default ( "domcontentloaded" ) ,
115+ waitUntil : z
116+ . enum ( [ "load" , "domcontentloaded" , "networkidle" , "commit" ] )
117+ . default ( "domcontentloaded" ) ,
103118 timeout : z . number ( ) . min ( 0 ) . max ( 120000 ) . default ( 30000 ) ,
104119 // Additional options
105120 deviceScaleFactor : z . number ( ) . min ( 0.1 ) . max ( 3 ) . default ( 1 ) ,
@@ -110,7 +125,7 @@ router.post(
110125 "/v1/screenshots" ,
111126 defineEventHandler ( async ( event ) => {
112127 const body = await readValidatedBody ( event , screenshotSchema . parse ) ;
113-
128+
114129 // Build context options
115130 const contextOptions = {
116131 ...defaultContext ,
@@ -193,53 +208,64 @@ const lighthouseSchema = z.object({
193208 headers : z . record ( z . string ( ) , z . any ( ) ) . optional ( ) ,
194209 userAgent : z . string ( ) . optional ( ) ,
195210 locale : z . string ( ) . optional ( ) ,
196- timezoneId : z . string ( ) . regex (
197- / ^ ( A f r i c a | A m e r i c a | A n t a r c t i c a | A r c t i c | A s i a | A t l a n t i c | A u s t r a l i a | E u r o p e | I n d i a n | P a c i f i c | U T C ) \/ [ A - Z a - z _ ] + $ / ,
198- "Must be a valid IANA timezone identifier (e.g., 'America/New_York', 'Europe/London', 'Asia/Tokyo')"
199- ) . optional ( ) ,
200- permissions : z . array ( z . enum ( [
201- "geolocation" ,
202- "camera" ,
203- "microphone" ,
204- "notifications" ,
205- "clipboard-read" ,
206- "clipboard-write" ,
207- "payment-handler" ,
208- "midi" ,
209- "usb" ,
210- "serial" ,
211- "bluetooth" ,
212- "persistent-storage" ,
213- "accelerometer" ,
214- "gyroscope" ,
215- "magnetometer" ,
216- "ambient-light-sensor" ,
217- "background-sync" ,
218- "background-fetch" ,
219- "idle-detection" ,
220- "periodic-background-sync" ,
221- "push" ,
222- "speaker-selection" ,
223- "storage-access" ,
224- "top-level-storage-access" ,
225- "window-management" ,
226- "local-fonts" ,
227- "display-capture" ,
228- "nfc" ,
229- "screen-wake-lock" ,
230- "web-share" ,
231- "xr-spatial-tracking"
232- ] ) ) . optional ( ) ,
211+ timezoneId : z
212+ . string ( )
213+ . regex (
214+ / ^ ( A f r i c a | A m e r i c a | A n t a r c t i c a | A r c t i c | A s i a | A t l a n t i c | A u s t r a l i a | E u r o p e | I n d i a n | P a c i f i c | U T C ) \/ [ A - Z a - z _ ] + $ / ,
215+ "Must be a valid IANA timezone identifier (e.g., 'America/New_York', 'Europe/London', 'Asia/Tokyo')" ,
216+ )
217+ . optional ( ) ,
218+ permissions : z
219+ . array (
220+ z . enum ( [
221+ "geolocation" ,
222+ "camera" ,
223+ "microphone" ,
224+ "notifications" ,
225+ "clipboard-read" ,
226+ "clipboard-write" ,
227+ "payment-handler" ,
228+ "midi" ,
229+ "usb" ,
230+ "serial" ,
231+ "bluetooth" ,
232+ "persistent-storage" ,
233+ "accelerometer" ,
234+ "gyroscope" ,
235+ "magnetometer" ,
236+ "ambient-light-sensor" ,
237+ "background-sync" ,
238+ "background-fetch" ,
239+ "idle-detection" ,
240+ "periodic-background-sync" ,
241+ "push" ,
242+ "speaker-selection" ,
243+ "storage-access" ,
244+ "top-level-storage-access" ,
245+ "window-management" ,
246+ "local-fonts" ,
247+ "display-capture" ,
248+ "nfc" ,
249+ "screen-wake-lock" ,
250+ "web-share" ,
251+ "xr-spatial-tracking" ,
252+ ] ) ,
253+ )
254+ . optional ( ) ,
233255 // Performance thresholds
234- thresholds : z . object ( {
235- performance : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
236- accessibility : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
237- "best-practices" : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
238- seo : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
239- pwa : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
240- } ) . optional ( ) ,
256+ thresholds : z
257+ . object ( {
258+ performance : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
259+ accessibility : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
260+ "best-practices" : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
261+ seo : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
262+ pwa : z . number ( ) . min ( 0 ) . max ( 100 ) . default ( 0 ) ,
263+ } )
264+ . optional ( ) ,
241265 // Navigation options
242- waitUntil : z . enum ( [ "load" , "domcontentloaded" , "networkidle" , "commit" ] ) . default ( "domcontentloaded" ) ,
266+ waitUntil : z
267+ . enum ( [ "load" , "domcontentloaded" , "networkidle" , "commit" ] )
268+ . default ( "domcontentloaded" ) ,
243269 timeout : z . number ( ) . min ( 0 ) . max ( 120000 ) . default ( 30000 ) ,
244270} ) ;
245271const configs = {
@@ -250,7 +276,7 @@ router.post(
250276 "/v1/reports" ,
251277 defineEventHandler ( async ( event ) => {
252278 const body = await readValidatedBody ( event , lighthouseSchema . parse ) ;
253-
279+
254280 // Build context options
255281 const contextOptions = {
256282 ...defaultContext ,
@@ -683,9 +709,9 @@ router.get(
683709 } ) ;
684710
685711 await context . close ( ) ;
686-
712+
687713 // Set content type to HTML
688- event . node . res . setHeader ( ' Content-Type' , ' text/html' ) ;
714+ event . node . res . setHeader ( " Content-Type" , " text/html" ) ;
689715 return html ;
690716 } ) ,
691717) ;
0 commit comments