/** * Dev-only runner for the BOUNTY HUNT in-browser probe (dev/bounty-hunt-shot.mjs). * * node dev/server.mjs 8080 # the no-store dev server * CHROME_PATH=/path/to/chrome node dev/bounty-hunt-shot-run.mjs [baseUrl] * * Loads each stage in a real headless Chromium, waits for the page's own * report (window.__BH), writes dev/shots/bh-.json + .png for every * stage, and prints one line per stage. Exit 0 only when no stage FAILED and * no page error was captured. */ import fs from 'node:fs'; import path from 'node:path'; import { launch, CDP } from './cdpshot.mjs'; const BASE = process.argv[2] || 'http://127.0.0.1:8080/dev/bounty-hunt-shot.html'; const STAGES = ['locked', 'dossier', 'hunt', 'mark']; const OUT = path.resolve('dev/shots'); const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); fs.mkdirSync(OUT, { recursive: true }); let bad = 0; for (const stage of STAGES) { const url = `${BASE}#${stage}`; const { url: wsUrl, kill } = await launch(url); const cdp = new CDP(wsUrl); try { await cdp.open(); await cdp.send('Runtime.enable'); await cdp.send('Page.enable'); let rep = null; const t0 = Date.now(); while (Date.now() - t0 < 180000) { try { const r = await cdp.send('Runtime.evaluate', { expression: 'window.__BH && window.__BH.stage && window.__BH.stage !== "running" ? JSON.stringify(window.__BH) : null', returnByValue: true }); if (r.result?.value) { rep = JSON.parse(r.result.value); break; } } catch { /* still booting */ } await sleep(500); } if (!rep) { bad++; console.log(`${stage.padEnd(8)} ✘ TIMEOUT — the page never reported`); continue; } const shot = await cdp.send('Page.captureScreenshot', { format: 'png' }); fs.writeFileSync(path.join(OUT, `bh-${stage}.png`), Buffer.from(shot.data, 'base64')); fs.writeFileSync(path.join(OUT, `bh-${stage}.json`), JSON.stringify(rep, null, 1)); if (rep.stage === 'FAILED' || (rep.errors && rep.errors.length)) bad++; console.log(`${stage.padEnd(8)} ${rep.stage === 'FAILED' ? '✘ FAILED' : '✔'} ${JSON.stringify(rep).slice(0, 240)}`); } finally { cdp.close(); kill(); await sleep(400); } } console.log(bad ? `\n${bad} stage(s) need attention` : '\nall BOUNTY HUNT browser stages reported clean'); process.exitCode = bad ? 1 : 0;