feat: 内置受管浏览器(CDP + AX 快照 ref 体系)+ 本地浏览器配置导入
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* CDP 命令的基础设施:超时与中止。
|
||||
*
|
||||
* Electron Debugger 的 sendCommand 在目标页面卡死或 DevTools 通道异常时可能永不
|
||||
* settle;超时/中止只让调用方继续执行,底层命令后续 settle 时会被安全忽略。
|
||||
*/
|
||||
|
||||
export const BROWSER_CDP_COMMAND_TIMEOUT_MS = 8_000
|
||||
export const BROWSER_OBSERVE_TIMEOUT_MS = 5_000
|
||||
export const BROWSER_OBSERVE_AX_DEPTH = 8
|
||||
export const BROWSER_OBSERVE_EXTENDED_AX_DEPTH = 16
|
||||
|
||||
/** 高预算 Observe 读取更深的 AX tree,常规观察保持紧凑避免 Chromium 长时间阻塞 */
|
||||
export function resolveBrowserObserveAxDepth(maxElements: number): number {
|
||||
return maxElements > 240 ? BROWSER_OBSERVE_EXTENDED_AX_DEPTH : BROWSER_OBSERVE_AX_DEPTH
|
||||
}
|
||||
|
||||
export class BrowserCdpTimeoutError extends Error {
|
||||
constructor(method: string, timeoutMs: number) {
|
||||
super(`浏览器页面未在 ${Math.ceil(timeoutMs / 1_000)} 秒内响应 ${method},请稍后重试或重新加载页面。`)
|
||||
this.name = 'BrowserCdpTimeoutError'
|
||||
}
|
||||
}
|
||||
|
||||
/** 已发出的 DevTools 命令无法撤销;该错误只保证不再执行后续页面动作 */
|
||||
export class BrowserOperationAbortedError extends Error {
|
||||
constructor() {
|
||||
super('浏览器操作已停止。已发送的页面指令可能已执行,页面状态请重新观察确认。')
|
||||
this.name = 'BrowserOperationAbortedError'
|
||||
}
|
||||
}
|
||||
|
||||
export function throwIfBrowserOperationAborted(signal?: AbortSignal): void {
|
||||
if (signal?.aborted) throw new BrowserOperationAbortedError()
|
||||
}
|
||||
|
||||
export interface CdpResponse {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export function withBrowserCdpTimeout<T>(
|
||||
command: () => Promise<T>,
|
||||
method: string,
|
||||
timeoutMs: number = BROWSER_CDP_COMMAND_TIMEOUT_MS
|
||||
): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
let settled = false
|
||||
const settle = (callback: () => void): void => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
clearTimeout(timer)
|
||||
callback()
|
||||
}
|
||||
const timer = setTimeout(() => settle(() => reject(new BrowserCdpTimeoutError(method, timeoutMs))), timeoutMs)
|
||||
void Promise.resolve()
|
||||
.then(command)
|
||||
.then((value) => settle(() => resolve(value)))
|
||||
.catch((error: unknown) => settle(() => reject(error)))
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user