import fs from 'fs'; import path from 'path'; import nodemailer from 'nodemailer'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const urls = [ 'https://andreknie.de', 'https://api.andreknie.de', 'https://notes.andreknie.de', 'https://unikat.andreknie.de', 'https://projekt-kiq.d-hive.de', 'https://d-hive.de' ]; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function checkUrl(url) { try { const res = await fetch(url, { method: 'GET', redirect: 'follow' }); if (res.ok) { return { url, status: 'UP', code: res.status }; } else { return { url, status: 'DOWN', code: res.status }; } } catch (err) { return { url, status: 'DOWN', error: err.message }; } } async function sendAlert(failedUrls) { const { SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, STAKEHOLDER_EMAIL } = process.env; if (!SMTP_HOST || !SMTP_USER || !SMTP_PASS || !STAKEHOLDER_EMAIL) { console.error('SMTP credentials missing. Cannot send alert email.'); return; } const transporter = nodemailer.createTransport({ host: SMTP_HOST, port: parseInt(SMTP_PORT || '587', 10), secure: parseInt(SMTP_PORT || '587', 10) === 465, auth: { user: SMTP_USER, pass: SMTP_PASS, }, }); const urlList = failedUrls.map(f => `- ${f.url} (Code: ${f.code || f.error})`).join('\n'); try { await transporter.sendMail({ from: `"Smoketest Alert" <${SMTP_USER}>`, to: STAKEHOLDER_EMAIL, subject: '🚨 Smoketest Alert: Endpoints Down', text: `The following endpoints failed after two attempts:\n\n${urlList}`, }); console.log('Alert email sent.'); } catch (err) { console.error('Failed to send alert email:', err); } } async function generateDashboard(results) { const html = ` Smoketest Dashboard

Smoketest Dashboard

${results.map(r => ` `).join('')}
URL Status Details
${r.url} ${r.status} ${r.status === 'UP' ? `HTTP ${r.code}` : (r.code ? `HTTP ${r.code}` : r.error)}
`; // Write to a separate directory to avoid interfering with Vite's public dir if we run locally const outDir = path.join(__dirname, '..', 'public-dashboard'); if (!fs.existsSync(outDir)) { fs.mkdirSync(outDir, { recursive: true }); } fs.writeFileSync(path.join(outDir, 'index.html'), html); console.log('Dashboard generated at public-dashboard/index.html'); } async function main() { console.log('Starting smoketest...'); const results = []; const failedFirstTry = []; for (const url of urls) { const result = await checkUrl(url); if (result.status === 'DOWN') { console.log(`❌ ${url} is DOWN (First Try)`); failedFirstTry.push(result); } else { console.log(`✅ ${url} is UP`); results.push(result); } } const finalFailures = []; if (failedFirstTry.length > 0) { console.log(`\nWaiting 5 minutes before retrying ${failedFirstTry.length} failed endpoints...`); // Wait 5 minutes await sleep(5 * 60 * 1000); console.log('\nRetrying failed endpoints...'); for (const f of failedFirstTry) { const result = await checkUrl(f.url); if (result.status === 'DOWN') { console.log(`❌ ${f.url} is DOWN (Second Try)`); finalFailures.push(result); results.push(result); } else { console.log(`✅ ${f.url} is UP (Second Try)`); results.push(result); } } } // Generate Dashboard await generateDashboard(results); // Alert if needed if (finalFailures.length > 0) { await sendAlert(finalFailures); process.exit(1); } else { console.log('All endpoints are UP.'); } } main().catch(err => { console.error('Unexpected error:', err); process.exit(1); });