#!/usr/bin/env node /** * Tilbudgivern Debug Tool * Et avanceret diagnosticering værktøj for at identificere problemer */ const http = require('http'); const { spawn } = require('child_process'); class DebugTool { constructor() { this.tests = [ { name: 'Server Health Check', method: 'checkServer' }, { name: 'Frontend Assets Check', method: 'checkAssets' }, { name: 'API Endpoints Check', method: 'checkAPI' }, { name: 'Database Connection', method: 'checkDatabase' }, { name: 'PM2 Process Status', method: 'checkPM2' }, { name: 'Recent Error Analysis', method: 'analyzeErrors' } ]; } async run() { console.log('\n🔧 Tilbudgivern Advanced Debug Tool\n'); console.log('═'.repeat(50)); for (const test of this.tests) { try { console.log(`\n📋 ${test.name}...`); await this[test.method](); console.log('✅ PASSED'); } catch (error) { console.log(`❌ FAILED: ${error.message}`); } } console.log('\n' + '═'.repeat(50)); console.log('🎯 Debug Complete! Tjek resultaterne ovenfor.\n'); } checkServer() { return new Promise((resolve, reject) => { const req = http.get('http://localhost:4030', (res) => { if (res.statusCode === 200) { console.log(` Status: ${res.statusCode} OK`); console.log(` Headers: ${JSON.stringify(res.headers, null, 2)}`); resolve(); } else { reject(new Error(`Server returned ${res.statusCode}`)); } }); req.on('error', (err) => { reject(new Error(`Connection failed: ${err.message}`)); }); req.setTimeout(5000, () => { reject(new Error('Request timeout')); }); }); } checkAssets() { return new Promise((resolve, reject) => { // Check main JS file const req = http.get('http://localhost:4030/static/js/main.a016d298.js', (res) => { if (res.statusCode === 200) { console.log(' React JS bundle: ✅ Loaded'); // Check CSS file const cssReq = http.get('http://localhost:4030/static/css/main.a0ad9f95.css', (cssRes) => { if (cssRes.statusCode === 200) { console.log(' CSS bundle: ✅ Loaded'); resolve(); } else { reject(new Error(`CSS bundle failed: ${cssRes.statusCode}`)); } }); cssReq.on('error', (err) => reject(new Error(`CSS error: ${err.message}`))); } else { reject(new Error(`JS bundle failed: ${res.statusCode}`)); } }); req.on('error', (err) => reject(new Error(`Asset check error: ${err.message}`))); }); } async checkAPI() { const endpoints = [ '/api/materials', '/api/material-packages', '/api/quotes' ]; for (const endpoint of endpoints) { try { await this.testEndpoint(endpoint); console.log(` ${endpoint}: ✅ Responding`); } catch (error) { console.log(` ${endpoint}: ❌ ${error.message}`); } } } testEndpoint(path) { return new Promise((resolve, reject) => { const req = http.get(`http://localhost:4030${path}`, (res) => { if (res.statusCode < 500) { resolve(); } else { reject(new Error(`Server error ${res.statusCode}`)); } }); req.on('error', (err) => reject(new Error(err.message))); req.setTimeout(3000, () => reject(new Error('Timeout'))); }); } async checkDatabase() { return new Promise((resolve, reject) => { // Test database connection via API const req = http.get('http://localhost:4030/api/materials?limit=1', (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => { try { const result = JSON.parse(data); if (Array.isArray(result)) { console.log(' Database: ✅ Connected and responding'); console.log(` Sample data: ${result.length} materials available`); resolve(); } else { reject(new Error('Unexpected response format')); } } catch (error) { reject(new Error(`Parse error: ${error.message}`)); } }); }); req.on('error', (err) => reject(new Error(`DB test failed: ${err.message}`))); }); } async checkPM2() { return new Promise((resolve, reject) => { const pm2 = spawn('pm2', ['status'], { stdio: 'pipe' }); let output = ''; pm2.stdout.on('data', (data) => output += data); pm2.stderr.on('data', (data) => output += data); pm2.on('close', (code) => { if (code === 0) { console.log(' PM2 Status:'); const lines = output.split('\n'); lines.forEach(line => { if (line.includes('tilbudgivern') || line.includes('online') || line.includes('stopped')) { console.log(` ${line}`); } }); resolve(); } else { reject(new Error(`PM2 command failed with code ${code}`)); } }); }); } async analyzeErrors() { return new Promise((resolve, reject) => { const pm2 = spawn('pm2', ['logs', 'tilbudgivern-unified', '--lines', '50', '--nostream'], { stdio: 'pipe' }); let output = ''; pm2.stdout.on('data', (data) => output += data); pm2.stderr.on('data', (data) => output += data); pm2.on('close', (code) => { const errors = output.split('\n').filter(line => line.toLowerCase().includes('error') || line.toLowerCase().includes('failed') || line.toLowerCase().includes('exception') ); if (errors.length > 0) { console.log(` Recent Errors (${errors.length} found):`); errors.slice(-5).forEach(error => { console.log(` ${error.trim()}`); }); } else { console.log(' No recent errors found'); } resolve(); }); }); } } // Kør debug tool if (require.main === module) { const debugTool = new DebugTool(); debugTool.run().catch(console.error); } module.exports = DebugTool;