import { NextResponse } from "next/server"; import { execInDevContainer } from "@/lib/dev-container"; /** * Executes a simple Playwright script inside the dev container to extract browser console logs. */ export async function toolBrowserConsole(projectId: string, url: string) { const script = ` const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); const errors = []; page.on('console', msg => { if (msg.type() === 'error') { errors.push(msg.text()); } }); page.on('pageerror', err => { errors.push(err.message); }); try { await page.goto('${url}', { waitUntil: 'networkidle', timeout: 15000 }); console.log(JSON.stringify({ ok: true, errors })); } catch (err) { console.log(JSON.stringify({ ok: false, error: err.message, errors })); } finally { await browser.close(); } })(); `; // Encode the script to base64 to bypass any shell quoting/escaping conflicts const scriptB64 = Buffer.from(script, "utf8").toString("base64"); const tempFile = `.vibn-console-${projectId}.js`; const setupCmd = `echo "${scriptB64}" | base64 -d > ${tempFile} && if [ ! -d "node_modules/playwright" ]; then npm install --no-save playwright && npx playwright install chromium; fi && node ${tempFile} && rm -f ${tempFile}`; try { const res = await execInDevContainer({ projectId, command: setupCmd, timeoutMs: 60000, // 60s since downloading chromium takes a moment on first run }); if (res.code !== 0) { return NextResponse.json( { error: "Failed to run browser test", details: res.stderr }, { status: 500 }, ); } const lines = res.stdout.trim().split("\n"); const jsonLine = lines[lines.length - 1]; let result; try { result = JSON.parse(jsonLine); } catch { result = { ok: false, error: "Could not parse browser output", raw: res.stdout, }; } return NextResponse.json({ result }); } catch (e) { return NextResponse.json( { error: e instanceof Error ? e.message : String(e) }, { status: 500 }, ); } } /** * Executes a simple Playwright script inside the dev container to extract the page title and status code. */ export async function toolBrowserNavigate(projectId: string, url: string) { const script = ` const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); try { const response = await page.goto('${url}', { waitUntil: 'domcontentloaded', timeout: 15000 }); const title = await page.title(); console.log(JSON.stringify({ ok: true, status: response ? response.status() : null, title })); } catch (err) { console.log(JSON.stringify({ ok: false, error: err.message })); } finally { await browser.close(); } })(); `; // Encode the script to base64 to bypass any shell quoting/escaping conflicts const scriptB64 = Buffer.from(script, "utf8").toString("base64"); const tempFile = `.vibn-navigate-${projectId}.js`; const setupCmd = `echo "${scriptB64}" | base64 -d > ${tempFile} && if [ ! -d "node_modules/playwright" ]; then npm install --no-save playwright && npx playwright install chromium; fi && node ${tempFile} && rm -f ${tempFile}`; try { const res = await execInDevContainer({ projectId, command: setupCmd, timeoutMs: 60000, }); if (res.code !== 0) { return NextResponse.json( { error: "Failed to navigate", details: res.stderr }, { status: 500 }, ); } const lines = res.stdout.trim().split("\n"); const jsonLine = lines[lines.length - 1]; let result; try { result = JSON.parse(jsonLine); } catch { result = { ok: false, error: "Could not parse browser output", raw: res.stdout, }; } return NextResponse.json({ result }); } catch (e) { return NextResponse.json( { error: e instanceof Error ? e.message : String(e) }, { status: 500 }, ); } }