16
16
* - Extension assets served from `./output/chrome-mv3-dev` via `/chrome-mv3-dev` route
17
17
*/
18
18
import { error } from 'node:console'
19
+ import { spawn } from 'node:child_process'
19
20
import fs from 'node:fs/promises'
20
21
import path from 'node:path'
21
22
import { fileURLToPath } from 'node:url'
@@ -27,6 +28,9 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
27
28
const app = express ( )
28
29
const PORT = 3001
29
30
31
+ // Middleware to parse JSON bodies
32
+ app . use ( express . json ( ) )
33
+
30
34
// Store HAR json
31
35
const harCache = new Map < keyof typeof PAGES , Har > ( )
32
36
@@ -239,6 +243,63 @@ app.get('/asset/:key/*', async (req, res) => {
239
243
// Serve extension assets from filesystem
240
244
app . use ( '/chrome-mv3-dev' , express . static ( path . join ( __dirname , '..' , '.output' , 'chrome-mv3-dev' ) ) )
241
245
246
+ // Rebuild endpoint
247
+ app . post ( '/rebuild' , async ( req , res ) => {
248
+ try {
249
+ console . log ( 'Rebuild triggered via API' )
250
+
251
+ // Run npx wxt build --mode development
252
+ const buildProcess = spawn ( 'npx' , [ 'wxt' , 'build' , '--mode' , 'development' ] , {
253
+ cwd : path . join ( __dirname , '..' ) ,
254
+ stdio : [ 'pipe' , 'pipe' , 'pipe' ]
255
+ } )
256
+
257
+ let stdout = ''
258
+ let stderr = ''
259
+
260
+ buildProcess . stdout . on ( 'data' , ( data ) => {
261
+ stdout += data . toString ( )
262
+ console . log ( '[BUILD]' , data . toString ( ) . trim ( ) )
263
+ } )
264
+
265
+ buildProcess . stderr . on ( 'data' , ( data ) => {
266
+ stderr += data . toString ( )
267
+ console . error ( '[BUILD ERROR]' , data . toString ( ) . trim ( ) )
268
+ } )
269
+
270
+ buildProcess . on ( 'close' , ( code ) => {
271
+ if ( code === 0 ) {
272
+ console . log ( 'Build completed successfully' )
273
+ res . json ( { success : true , message : 'Build completed successfully' } )
274
+ } else {
275
+ console . error ( 'Build failed with code:' , code )
276
+ res . status ( 500 ) . json ( {
277
+ success : false ,
278
+ message : 'Build failed' ,
279
+ error : stderr || stdout
280
+ } )
281
+ }
282
+ } )
283
+
284
+ buildProcess . on ( 'error' , ( error ) => {
285
+ console . error ( 'Failed to start build process:' , error )
286
+ res . status ( 500 ) . json ( {
287
+ success : false ,
288
+ message : 'Failed to start build process' ,
289
+ error : error . message
290
+ } )
291
+ } )
292
+
293
+ } catch ( error ) {
294
+ console . error ( 'Rebuild endpoint error:' , error )
295
+ res . status ( 500 ) . json ( {
296
+ success : false ,
297
+ message : 'Internal server error' ,
298
+ error : error instanceof Error ? error . message : 'Unknown error'
299
+ } )
300
+ }
301
+ } )
302
+
242
303
app . listen ( PORT , ( ) => {
243
304
console . log ( `HAR Page Viewer running at http://localhost:${ PORT } ` )
244
305
console . log ( 'Click the links to view recorded pages' )
@@ -296,6 +357,90 @@ function injectGitcassoScript(key: keyof typeof PAGES, html: string) {
296
357
.catch(error => {
297
358
console.error('Failed to load and patch content script:', error);
298
359
});
360
+
361
+ // Create floating rebuild button
362
+ const rebuildButton = document.createElement('div');
363
+ rebuildButton.id = 'gitcasso-rebuild-btn';
364
+ rebuildButton.innerHTML = '🔄';
365
+ rebuildButton.title = 'Rebuild Extension';
366
+ rebuildButton.style.cssText = \`
367
+ position: fixed;
368
+ top: 20px;
369
+ right: 20px;
370
+ width: 50px;
371
+ height: 50px;
372
+ background: #007acc;
373
+ color: white;
374
+ border-radius: 50%;
375
+ display: flex;
376
+ align-items: center;
377
+ justify-content: center;
378
+ font-size: 20px;
379
+ cursor: pointer;
380
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
381
+ z-index: 999999;
382
+ user-select: none;
383
+ transition: all 0.2s ease;
384
+ font-family: system-ui, -apple-system, sans-serif;
385
+ \`;
386
+
387
+ rebuildButton.addEventListener('mouseenter', () => {
388
+ rebuildButton.style.transform = 'scale(1.1)';
389
+ rebuildButton.style.backgroundColor = '#005a9e';
390
+ });
391
+
392
+ rebuildButton.addEventListener('mouseleave', () => {
393
+ rebuildButton.style.transform = 'scale(1)';
394
+ rebuildButton.style.backgroundColor = '#007acc';
395
+ });
396
+
397
+ rebuildButton.addEventListener('click', async () => {
398
+ try {
399
+ rebuildButton.innerHTML = '⏳';
400
+ rebuildButton.style.backgroundColor = '#ffa500';
401
+ rebuildButton.title = 'Rebuilding...';
402
+
403
+ const response = await fetch('/rebuild', {
404
+ method: 'POST',
405
+ headers: { 'Content-Type': 'application/json' }
406
+ });
407
+
408
+ const result = await response.json();
409
+
410
+ if (result.success) {
411
+ rebuildButton.innerHTML = '✅';
412
+ rebuildButton.style.backgroundColor = '#28a745';
413
+ rebuildButton.title = 'Build successful! Reloading...';
414
+
415
+ setTimeout(() => {
416
+ location.reload(true);
417
+ }, 1000);
418
+ } else {
419
+ rebuildButton.innerHTML = '❌';
420
+ rebuildButton.style.backgroundColor = '#dc3545';
421
+ rebuildButton.title = 'Build failed: ' + (result.error || result.message);
422
+
423
+ setTimeout(() => {
424
+ rebuildButton.innerHTML = '🔄';
425
+ rebuildButton.style.backgroundColor = '#007acc';
426
+ rebuildButton.title = 'Rebuild Extension';
427
+ }, 3000);
428
+ }
429
+ } catch (error) {
430
+ console.error('Rebuild failed:', error);
431
+ rebuildButton.innerHTML = '❌';
432
+ rebuildButton.style.backgroundColor = '#dc3545';
433
+ rebuildButton.title = 'Network error: ' + error.message;
434
+
435
+ setTimeout(() => {
436
+ rebuildButton.innerHTML = '🔄';
437
+ rebuildButton.style.backgroundColor = '#007acc';
438
+ rebuildButton.title = 'Rebuild Extension';
439
+ }, 3000);
440
+ }
441
+ });
442
+
443
+ document.body.appendChild(rebuildButton);
299
444
</script>
300
445
`
301
446
if ( ! html . includes ( '</body>' ) ) {
0 commit comments