@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url'
44import  express  from  'express' 
55import  type  {  Har  }  from  'har-format' 
66import  {  PAGES  }  from  './har-index' 
7+ import  {  error  }  from  'node:console' 
78
89const  __dirname  =  path . dirname ( fileURLToPath ( import . meta. url ) ) 
910const  app  =  express ( ) 
@@ -139,40 +140,83 @@ app.get('/har/:key/:mode(clean|gitcasso)', async (req, res) => {
139140  try  { 
140141    const  key  =  req . params [ 'key' ]  as  keyof  typeof  PAGES 
141142    const  mode  =  req . params [ 'mode' ]  as  'clean'  |  'gitcasso' 
142- 
143143    if  ( ! ( key  in  PAGES ) )  { 
144144      return  res . status ( 400 ) . send ( 'Invalid key - not found in PAGES' ) 
145145    } 
146146
147-     const  harData  =  await  loadHar ( key ) 
148- 
149147    // Find the main HTML response 
148+     const  harData  =  await  loadHar ( key ) 
150149    const  mainEntry  =  harData . log . entries . find ( 
151150      ( entry )  => 
152151        entry . request . url . includes ( 'github.com' )  && 
153152        entry . response . content . mimeType ?. includes ( 'text/html' )  && 
154153        entry . response . content . text , 
155154    ) 
156- 
157155    if  ( ! mainEntry )  { 
158156      return  res . status ( 404 ) . send ( 'No HTML content found in HAR file' ) 
159157    } 
160158
161-     let  html  =  mainEntry . response . content . text ! 
162- 
163159    // Replace external URLs with local asset URLs 
160+     let  html  =  mainEntry . response . content . text ! 
164161    html  =  html . replace ( 
165162      / h t t p s : \/ \/ ( g i t h u b \. c o m | a s s e t s \. g i t h u b \. c o m | a v a t a r s \. g i t h u b u s e r c o n t e n t \. c o m | u s e r - i m a g e s \. g i t h u b u s e r c o n t e n t \. c o m ) / g, 
166163      `/asset/${ key }  , 
167164    ) 
168- 
169-     // If gitcasso mode, inject content script 
170165    if  ( mode  ===  'gitcasso' )  { 
171-       // Get original URL parts for location patching 
172-       const  urlParts  =  getUrlParts ( key ) 
166+       html  =  injectGitcassoScript ( key ,  html ) 
167+     } 
168+     return  res . send ( html ) 
169+   }  catch  ( error )  { 
170+     console . error ( 'Error serving page:' ,  error ) 
171+     return  res . status ( 500 ) . send ( 'Error loading page' ) 
172+   } 
173+ } ) 
174+ 
175+ // Serve assets from HAR file 
176+ app . get ( '/asset/:key/*' ,  async  ( req ,  res )  =>  { 
177+   try  { 
178+     const  key  =  req . params . key  as  keyof  typeof  PAGES 
179+     if  ( ! ( key  in  PAGES ) )  { 
180+       return  res . status ( 400 ) . send ( 'Invalid key - not found in PAGES' ) 
181+     } 
182+     const  assetPath  =  ( req . params  as  any ) [ 0 ]  as  string 
183+ 
184+     const  harData  =  await  loadHar ( key ) 
185+ 
186+     // Find matching asset in HAR 
187+     const  assetEntry  =  harData . log . entries . find ( ( entry )  =>  { 
188+       const  url  =  new  URL ( entry . request . url ) 
189+       return  url . pathname  ===  `/${ assetPath }   ||  url . pathname . endsWith ( `/${ assetPath }  ) 
190+     } ) 
191+ 
192+     if  ( ! assetEntry )  { 
193+       return  res . status ( 404 ) . send ( 'Asset not found' ) 
194+     } 
195+ 
196+     const  content  =  assetEntry . response . content 
197+     const  mimeType  =  content . mimeType  ||  'application/octet-stream' 
198+     res . set ( 'Content-Type' ,  mimeType ) 
199+     if  ( content . encoding  ===  'base64' )  { 
200+       return  res . send ( Buffer . from ( content . text ! ,  'base64' ) ) 
201+     }  else  { 
202+       return  res . send ( content . text ! ) 
203+     } 
204+   }  catch  ( error )  { 
205+     console . error ( 'Error serving asset:' ,  error ) 
206+     return  res . status ( 404 ) . send ( 'Asset not found' ) 
207+   } 
208+ } ) 
173209
174-       // Inject patched content script with location patching 
175-       const  contentScriptTag  =  ` 
210+ app . listen ( PORT ,  ( )  =>  { 
211+   console . log ( `HAR Page Viewer running at http://localhost:${ PORT }  ) 
212+   console . log ( 'Click the links to view recorded pages' ) 
213+ } ) 
214+ 
215+ function  injectGitcassoScript ( key : keyof  typeof  PAGES ,  html : string )  { 
216+   const  urlParts  =  getUrlParts ( key ) 
217+ 
218+   // Inject patched content script with location patching 
219+   const  contentScriptTag  =  ` 
176220        <script> 
177221          // Patch window.location before loading content script 
178222          console.log('Patching window.location to simulate original URL...'); 
@@ -222,58 +266,9 @@ app.get('/har/:key/:mode(clean|gitcasso)', async (req, res) => {
222266            }); 
223267        </script> 
224268      ` 
225- 
226-       // Insert script before closing body tag, or at the end if no body tag 
227-       if  ( html . includes ( '</body>' ) )  { 
228-         html  =  html . replace ( '</body>' ,  `${ contentScriptTag }  ) 
229-       }  else  { 
230-         html  +=  contentScriptTag 
231-       } 
232-     } 
233- 
234-     return  res . send ( html ) 
235-   }  catch  ( error )  { 
236-     console . error ( 'Error serving page:' ,  error ) 
237-     return  res . status ( 500 ) . send ( 'Error loading page' ) 
269+   if  ( ! html . includes ( '</body>' ) )  { 
270+     throw  error ( 'No closing body tag, nowhere to put the content script!' ) 
238271  } 
239- } ) 
240- 
241- // Serve assets from HAR file 
242- app . get ( '/asset/:key/*' ,  async  ( req ,  res )  =>  { 
243-   try  { 
244-     const  key  =  req . params . key  as  keyof  typeof  PAGES 
245-     if  ( ! ( key  in  PAGES ) )  { 
246-       return  res . status ( 400 ) . send ( 'Invalid key - not found in PAGES' ) 
247-     } 
248-     const  assetPath  =  ( req . params  as  any ) [ 0 ]  as  string 
249- 
250-     const  harData  =  await  loadHar ( key ) 
251- 
252-     // Find matching asset in HAR 
253-     const  assetEntry  =  harData . log . entries . find ( ( entry )  =>  { 
254-       const  url  =  new  URL ( entry . request . url ) 
255-       return  url . pathname  ===  `/${ assetPath }   ||  url . pathname . endsWith ( `/${ assetPath }  ) 
256-     } ) 
257- 
258-     if  ( ! assetEntry )  { 
259-       return  res . status ( 404 ) . send ( 'Asset not found' ) 
260-     } 
261- 
262-     const  content  =  assetEntry . response . content 
263-     const  mimeType  =  content . mimeType  ||  'application/octet-stream' 
264-     res . set ( 'Content-Type' ,  mimeType ) 
265-     if  ( content . encoding  ===  'base64' )  { 
266-       return  res . send ( Buffer . from ( content . text ! ,  'base64' ) ) 
267-     }  else  { 
268-       return  res . send ( content . text ! ) 
269-     } 
270-   }  catch  ( error )  { 
271-     console . error ( 'Error serving asset:' ,  error ) 
272-     return  res . status ( 404 ) . send ( 'Asset not found' ) 
273-   } 
274- } ) 
272+   return  html . replace ( '</body>' ,  `${ contentScriptTag }  ) 
273+ } 
275274
276- app . listen ( PORT ,  ( )  =>  { 
277-   console . log ( `HAR Page Viewer running at http://localhost:${ PORT }  ) 
278-   console . log ( 'Click the links to view recorded GitHub pages' ) 
279- } ) 
0 commit comments