import type { BrowserWindow } from "electron"; import { RuntimeError, mapCdpError, type CdpEventHandler, type CdpTransport } from "@rpa/core"; /** * 内置运行浏览器传输层(宿主适配层,任务 2.3)。 * * 包装 Electron BrowserWindow.webContents.debugger,实现包内的 CdpTransport 接口; * CdpTransport / mapCdpError / ExternalTransport(外部浏览器)已迁入 @rpa/core。 */ export class EmbeddedTransport implements CdpTransport { readonly kind = "embedded" as const; private wrappers = new Map) => void>(); constructor(private win: BrowserWindow) {} get closed(): boolean { return this.win.isDestroyed(); } async send(method: string, params: Record = {}): Promise { if (this.win.isDestroyed()) { throw new RuntimeError("tab_unavailable", "运行浏览器已关闭", { recommendation: "重新运行流程" }); } try { if (!this.win.webContents.debugger.isAttached()) this.win.webContents.debugger.attach("1.3"); return (await this.win.webContents.debugger.sendCommand(method, params)) as T; } catch (error) { throw mapCdpError(error, "embedded"); } } on(method: string, handler: CdpEventHandler): void { if (this.win.isDestroyed()) return; const wrapper = (_event: unknown, evtMethod: string, evtParams?: Record) => { if (evtMethod === method) handler(evtParams ?? {}); }; this.wrappers.set(handler, wrapper); this.win.webContents.debugger.on("message", wrapper as never); } off(method: string, handler: CdpEventHandler): void { const wrapper = this.wrappers.get(handler); if (wrapper) { this.win.webContents.debugger.removeListener("message", wrapper as never); this.wrappers.delete(handler); } } async close(): Promise { if (!this.win.isDestroyed() && this.win.webContents.debugger.isAttached()) { try { this.win.webContents.debugger.detach(); } catch { // 窗口关闭过程中 detach 可能失败,忽略 } } } }