import fs from "node:fs"; import type { Page } from "playwright"; export type ConsoleEvent = { ts: number; iso: string; phase: string; type: string; text: string; location?: string; }; export class ConsoleLogger { private phase = "recording_start"; constructor(private readonly outPath: string) { fs.mkdirSync(dirname(outPath), { recursive: true }); } setPhase(phase: string): void { this.phase = phase; } attach(page: Page): void { page.on("console", (msg) => { const entry: ConsoleEvent = { ts: Date.now(), iso: new Date().toISOString(), phase: this.phase, type: msg.type(), text: msg.text().slice(0, 2000), location: msg.location()?.url, }; fs.appendFileSync(this.outPath, `${JSON.stringify(entry)}\n`, "utf8"); }); page.on("pageerror", (error) => { const entry: ConsoleEvent = { ts: Date.now(), iso: new Date().toISOString(), phase: this.phase, type: "pageerror", text: error.message.slice(0, 2000), }; fs.appendFileSync(this.outPath, `${JSON.stringify(entry)}\n`, "utf8"); }); } } function dirname(filePath: string): string { const idx = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\")); return idx >= 0 ? filePath.slice(0, idx) : filePath; }