agent-go / src /app /api /screenshot /route.ts
arudradey's picture
Update src/app/api/screenshot/route.ts
58502d1 verified
import { NextResponse } from "next/server";
import { getPage } from "@/lib/browser";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
type ClickableElement = {
tag: string;
text: string;
x: number;
y: number;
width: number;
height: number;
type?: string;
href?: string;
};
export async function GET() {
try {
const page = getPage();
if (!page) {
return NextResponse.json(
{ error: "No active browser session" },
{ status: 400 }
);
}
const clickableElements = await page.evaluate(() => {
const selectors = [
"a",
"button",
"input",
"select",
"textarea",
"summary",
"label",
"[role='button']",
"[role='link']",
"[role='menuitem']",
"[role='tab']",
"[tabindex]",
"[onclick]",
"[contenteditable='true']",
];
const found: ClickableElement[] = [];
const seen = new Set<Element>();
const isVisible = (el: Element) => {
const rect = el.getBoundingClientRect();
if (rect.width < 4 || rect.height < 4) return false;
if (rect.bottom < 0 || rect.right < 0) return false;
if (rect.top > window.innerHeight || rect.left > window.innerWidth) return false;
const style = window.getComputedStyle(el as HTMLElement);
if (style.visibility === "hidden" || style.display === "none") return false;
if (style.pointerEvents === "none") return false;
return true;
};
for (const selector of selectors) {
document.querySelectorAll(selector).forEach((el) => {
if (seen.has(el)) return;
seen.add(el);
if (!isVisible(el)) return;
const rect = el.getBoundingClientRect();
const htmlEl = el as HTMLElement;
const text =
(htmlEl.innerText || htmlEl.textContent || "").trim().slice(0, 100) ||
htmlEl.getAttribute("aria-label") ||
htmlEl.getAttribute("title") ||
htmlEl.getAttribute("placeholder") ||
"";
found.push({
tag: el.tagName.toLowerCase(),
text,
x: Math.round(rect.left),
y: Math.round(rect.top),
width: Math.round(rect.width),
height: Math.round(rect.height),
type:
"type" in el && typeof (el as HTMLInputElement).type === "string"
? (el as HTMLInputElement).type
: undefined,
href:
el instanceof HTMLAnchorElement && el.href
? el.href
: undefined,
});
});
}
return found.slice(0, 200);
});
const viewport = page.viewportSize() || { width: 1280, height: 720 };
const screenshotBuffer = await page.screenshot({
type: "png",
fullPage: false,
animations: "disabled",
});
const screenshot = screenshotBuffer.toString("base64");
return NextResponse.json({
screenshot,
clickableElements,
width: viewport.width,
height: viewport.height,
});
} catch (e: unknown) {
const message = e instanceof Error ? e.message : "Unknown error";
console.error("[/api/screenshot]", message);
return NextResponse.json({ error: message }, { status: 500 });
}
}