import { Kernel } from "@onkernel/sdk";
import fs from "fs";
import pTimeout from "p-timeout";
import { chromium } from "playwright";
const DOWNLOAD_DIR = "/tmp/downloads";
const kernel = new Kernel();
async function main() {
const kernelBrowser = await kernel.browsers.create();
console.log("live view:", kernelBrowser.browser_live_view_url);
const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);
const context = (await browser.contexts()[0]) || (await browser.newContext());
const page = (await context.pages()[0]) || (await context.newPage());
// Required to prevent Playwright from overriding the location of the downloaded file
const client = await context.newCDPSession(page);
await client.send("Browser.setDownloadBehavior", {
behavior: "allow",
downloadPath: DOWNLOAD_DIR,
eventsEnabled: true,
});
// Set up CDP listeners to capture download filename and completion
let downloadFilename: string | undefined;
let downloadCompletedResolve!: () => void;
const downloadCompleted = new Promise<void>((resolve) => {
downloadCompletedResolve = resolve;
});
client.on("Browser.downloadWillBegin", (event) => {
downloadFilename = event.suggestedFilename ?? "unknown";
console.log("Download started:", downloadFilename);
});
client.on("Browser.downloadProgress", (event) => {
if (event.state === "completed" || event.state === "canceled") {
downloadCompletedResolve();
}
});
// Trigger the download in the page
console.log("Navigating to download test page");
await page.goto("https://browser-tests-alpha.vercel.app/api/download-test");
await page.getByRole("link", { name: "Download File" }).click();
try {
await pTimeout(downloadCompleted, {
milliseconds: 10_000,
message: new Error("Download timed out after 10 seconds"),
});
console.log("Download completed");
} catch (err) {
console.error(err);
throw err;
}
if (!downloadFilename) {
throw new Error("Unable to determine download filename");
}
// Download the file directly from the browser instance
const remotePath = `${DOWNLOAD_DIR}/${downloadFilename}`;
console.log(`Reading file: ${remotePath}`);
const resp = await kernel.browsers.fs.readFile(kernelBrowser.session_id, {
path: remotePath,
});
const bytes = await resp.bytes();
fs.mkdirSync("downloads", { recursive: true });
const localPath = `downloads/${downloadFilename}`;
fs.writeFileSync(localPath, bytes);
console.log(`Saved to ${localPath}`);
// Alternatively, stream directly to disk:
// import { pipeline } from 'node:stream/promises';
// import { createWriteStream } from 'node:fs';
// import { Readable } from 'node:stream';
// await pipeline(Readable.fromWeb(resp.body!), createWriteStream(localPath));
await browser.close();
}
main();