#!/usr/bin/env node /** * validate-storybook: build Storybook, serve on 6007, run audit, then stop server. * Single command for CI/local: npm run validate:storybook */ const { spawn, execSync } = require('child_process'); const http = require('http'); const path = require('path'); const PORT = 6007; const INDEX_URL = `http://localhost:${PORT}/index.json`; const POLL_MS = 500; const POLL_TIMEOUT_MS = 60000; function waitForUrl(url, timeoutMs) { const start = Date.now(); return new Promise((resolve, reject) => { const tryOnce = () => { const req = http.get(url, (res) => { if (res.statusCode === 200) { resolve(); return; } res.resume(); schedule(); }); req.on('error', () => schedule()); req.setTimeout(5000, () => { req.destroy(); schedule(); }); }; const schedule = () => { if (Date.now() - start > timeoutMs) { reject(new Error(`Timeout waiting for ${url}`)); return; } setTimeout(tryOnce, POLL_MS); }; tryOnce(); }); } function runBuild() { console.log('[validate-storybook] Running build-storybook...'); execSync('npm run build-storybook', { stdio: 'inherit', cwd: path.resolve(__dirname, '..'), }); } function main() { const cwd = path.resolve(__dirname, '..'); runBuild(); const serve = spawn('npx', ['serve', 'storybook-static', '-l', String(PORT)], { stdio: 'pipe', shell: true, cwd, }); let auditExitCode = 1; serve.on('error', (err) => { console.error('[validate-storybook] Failed to start serve:', err); process.exit(1); }); waitForUrl(INDEX_URL, POLL_TIMEOUT_MS) .then(() => { console.log('[validate-storybook] Server ready, running audit...'); const audit = spawn('node', ['scripts/audit-storybook.js'], { stdio: 'inherit', shell: true, cwd, }); return new Promise((res) => { audit.on('exit', (code) => { auditExitCode = code ?? 1; res(); }); }); }) .catch((err) => { console.error('[validate-storybook]', err.message); auditExitCode = 1; }) .finally(() => { serve.kill('SIGTERM'); serve.on('exit', () => { process.exit(auditExitCode); }); setTimeout(() => { serve.kill('SIGKILL'); process.exit(auditExitCode); }, 5000); }); } main();