feat(*): svelte 5 panel view sharing the gateway ui, obsidian theme, preview and tests
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
// bun preview/shot.ts <out.png> <url> [width] [height]
|
||||
// Headless Chrome over CDP: the preview server must be running.
|
||||
const [out, url, w = "340", h = "720"] = process.argv.slice(2);
|
||||
const port = 9334;
|
||||
const proc = Bun.spawn(
|
||||
[
|
||||
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
||||
"--headless=new",
|
||||
"--disable-gpu",
|
||||
"--hide-scrollbars",
|
||||
`--remote-debugging-port=${port}`,
|
||||
`--window-size=${w},${h}`,
|
||||
"--user-data-dir=/tmp/beaver-preview-chrome",
|
||||
"about:blank",
|
||||
],
|
||||
{ stderr: "ignore", stdout: "ignore" }
|
||||
);
|
||||
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
let targets: { type: string; webSocketDebuggerUrl: string }[] = [];
|
||||
for (let i = 0; i < 40; i += 1) {
|
||||
try {
|
||||
// biome-ignore lint/performance/noAwaitInLoops: polling until Chrome is up
|
||||
targets = await (await fetch(`http://127.0.0.1:${port}/json`)).json();
|
||||
if (targets.length) {
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
/* not up yet */
|
||||
}
|
||||
await wait(250);
|
||||
}
|
||||
const page = targets.find((t) => t.type === "page");
|
||||
if (!page) {
|
||||
proc.kill();
|
||||
throw new Error("no page target");
|
||||
}
|
||||
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
||||
await new Promise((resolve) => {
|
||||
ws.onopen = resolve;
|
||||
});
|
||||
let id = 0;
|
||||
const pending = new Map<number, (v: { result?: { data?: string } }) => void>();
|
||||
ws.onmessage = (m) => {
|
||||
const d = JSON.parse(String(m.data));
|
||||
if (d.id && pending.has(d.id)) {
|
||||
pending.get(d.id)?.(d);
|
||||
pending.delete(d.id);
|
||||
}
|
||||
};
|
||||
const send = (method: string, params: Record<string, unknown> = {}) =>
|
||||
new Promise<{ result?: { data?: string } }>((resolve) => {
|
||||
id += 1;
|
||||
pending.set(id, resolve);
|
||||
ws.send(JSON.stringify({ id, method, params }));
|
||||
});
|
||||
await send("Emulation.setDeviceMetricsOverride", {
|
||||
deviceScaleFactor: 2,
|
||||
height: Number(h),
|
||||
mobile: Number(w) < 500,
|
||||
width: Number(w),
|
||||
});
|
||||
await send("Page.enable");
|
||||
await send("Page.navigate", { url });
|
||||
await wait(2500);
|
||||
if (process.env.EVAL) {
|
||||
const evaluated = await send("Runtime.evaluate", {
|
||||
expression: process.env.EVAL,
|
||||
returnByValue: true,
|
||||
});
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
(evaluated.result as { result?: { value?: unknown } }).result?.value
|
||||
)
|
||||
);
|
||||
await wait(400);
|
||||
}
|
||||
const shot = await send("Page.captureScreenshot", { format: "png" });
|
||||
await Bun.write(out, Buffer.from(shot.result?.data ?? "", "base64"));
|
||||
console.log(`wrote ${out}`);
|
||||
ws.close();
|
||||
proc.kill();
|
||||
Reference in New Issue
Block a user