147 lines
4.1 KiB
TypeScript
147 lines
4.1 KiB
TypeScript
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: true, load_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: true, load_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 },
|
|
);
|
|
}
|
|
}
|