import { NextRequest, NextResponse } from 'next/server' import { requireAuth } from '@/lib/auth' import lighthouse from 'lighthouse' import * as chromeLauncher from 'chrome-launcher' export const runtime = 'nodejs' const OPPORTUNITY_IDS = [ 'render-blocking-resources', 'unused-css-rules', 'unused-javascript', 'uses-optimized-images', 'uses-webp-images', 'uses-text-compression', 'uses-responsive-images', 'offscreen-images', 'server-response-time', 'redirects', 'efficient-animated-content', 'legacy-javascript', 'unminified-css', 'unminified-javascript', ] const DIAGNOSTIC_IDS = [ 'total-byte-weight', 'dom-size', 'bootup-time', 'mainthread-work-breakdown', 'font-display', 'third-party-summary', 'critical-request-chains', ] function pickAudit(audit: any) { if (!audit) return null return { id: audit.id, title: audit.title, description: audit.description, score: audit.score, scoreDisplayMode: audit.scoreDisplayMode, displayValue: audit.displayValue ?? null, numericValue: audit.numericValue ?? null, } } export async function GET(request: NextRequest) { const authErr = await requireAuth(request) if (authErr) return authErr const { searchParams } = new URL(request.url) const url = searchParams.get('url') const strategy = searchParams.get('strategy') || 'mobile' if (!url) { return NextResponse.json({ error: 'URL gerekli' }, { status: 400 }) } try { new URL(url) } catch { return NextResponse.json({ error: 'Geçersiz URL formatı' }, { status: 400 }) } let chrome: chromeLauncher.LaunchedChrome | undefined try { chrome = await chromeLauncher.launch({ chromeFlags: ['--headless', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'], }) const formFactor = strategy === 'desktop' ? 'desktop' : 'mobile' const screenEmulation = formFactor === 'desktop' ? { mobile: false, width: 1350, height: 940, deviceScaleFactor: 1, disabled: false } : { mobile: true, width: 375, height: 812, deviceScaleFactor: 3, disabled: false } // PSI ile eşleşen throttling değerleri const throttling = formFactor === 'desktop' ? { rttMs: 40, throughputKbps: 10_240, uploadThroughputKbps: 10_240, cpuSlowdownMultiplier: 1 } : { rttMs: 150, throughputKbps: 1_638.4, uploadThroughputKbps: 750, cpuSlowdownMultiplier: 4 } const runnerResult = await Promise.race([ lighthouse(url, { port: chrome.port, output: 'json', logLevel: 'error', formFactor, screenEmulation, throttling, throttlingMethod: 'simulate', }), new Promise((_, reject) => setTimeout(() => reject(new Error('Lighthouse zaman aşımına uğradı')), 60_000) ), ]) if (!runnerResult) throw new Error('Lighthouse sonuç döndürmedi') const { lhr } = runnerResult return NextResponse.json({ id: url, lighthouseResult: { categories: { performance: { score: lhr.categories?.performance?.score ?? 0 }, accessibility: { score: lhr.categories?.accessibility?.score ?? 0 }, 'best-practices': { score: lhr.categories?.['best-practices']?.score ?? 0 }, seo: { score: lhr.categories?.seo?.score ?? 0 }, }, audits: { 'first-contentful-paint': pickAudit(lhr.audits?.['first-contentful-paint']), 'largest-contentful-paint': pickAudit(lhr.audits?.['largest-contentful-paint']), 'total-blocking-time': pickAudit(lhr.audits?.['total-blocking-time']), 'cumulative-layout-shift': pickAudit(lhr.audits?.['cumulative-layout-shift']), 'speed-index': pickAudit(lhr.audits?.['speed-index']), 'interactive': pickAudit(lhr.audits?.['interactive']), }, opportunities: OPPORTUNITY_IDS .map(id => pickAudit(lhr.audits?.[id])) .filter((a): a is NonNullable => a !== null && a.score !== null && a.score < 0.9), diagnostics: DIAGNOSTIC_IDS .map(id => pickAudit(lhr.audits?.[id])) .filter((a): a is NonNullable => a !== null), }, }) } catch (error: any) { console.error('Lighthouse hatası:', error) return NextResponse.json( { error: error.message.includes('zaman aşımı') ? 'Analiz zaman aşımına uğradı, lütfen tekrar deneyin.' : 'Analiz sırasında hata oluştu. Sunucuda Chrome yüklü olduğundan emin olun.', details: error?.message || String(error) }, { status: 500 } ) } finally { await chrome?.kill() } }