99 */
1010
1111import { WebSocket , type RawData } from 'ws' ;
12- import type { IPage } from '../types.js' ;
12+ import type { BrowserCookie , IPage , ScreenshotOptions , SnapshotOptions , WaitOptions } from '../types.js' ;
1313import { wrapForEval } from './utils.js' ;
1414import { generateSnapshotJs , scrollToRefJs , getFormStateJs } from './dom-snapshot.js' ;
1515import {
@@ -29,13 +29,24 @@ export interface CDPTarget {
2929 webSocketDebuggerUrl ?: string ;
3030}
3131
32+ interface RuntimeEvaluateResult {
33+ result ?: {
34+ value ?: unknown ;
35+ } ;
36+ exceptionDetails ?: {
37+ exception ?: {
38+ description ?: string ;
39+ } ;
40+ } ;
41+ }
42+
3243const CDP_SEND_TIMEOUT = 30_000 ; // 30s per command
3344
3445export class CDPBridge {
3546 private _ws : WebSocket | null = null ;
3647 private _idCounter = 0 ;
37- private _pending = new Map < number , { resolve : ( val : any ) => void ; reject : ( err : Error ) => void ; timer : ReturnType < typeof setTimeout > } > ( ) ;
38- private _eventListeners = new Map < string , Set < ( params : any ) => void > > ( ) ;
48+ private _pending = new Map < number , { resolve : ( val : unknown ) => void ; reject : ( err : Error ) => void ; timer : ReturnType < typeof setTimeout > } > ( ) ;
49+ private _eventListeners = new Map < string , Set < ( params : unknown ) => void > > ( ) ;
3950
4051 async connect ( opts ?: { timeout ?: number ; workspace ?: string } ) : Promise < IPage > {
4152 const endpoint = process . env . OPENCLI_CDP_ENDPOINT ;
@@ -112,7 +123,7 @@ export class CDPBridge {
112123 }
113124
114125 /** Send a CDP command with timeout guard (P0 fix #4) */
115- async send ( method : string , params : any = { } , timeoutMs : number = CDP_SEND_TIMEOUT ) : Promise < any > {
126+ async send ( method : string , params : Record < string , unknown > = { } , timeoutMs : number = CDP_SEND_TIMEOUT ) : Promise < unknown > {
116127 if ( ! this . _ws || this . _ws . readyState !== WebSocket . OPEN ) {
117128 throw new Error ( 'CDP connection is not open' ) ;
118129 }
@@ -128,25 +139,25 @@ export class CDPBridge {
128139 }
129140
130141 /** Listen for a CDP event */
131- on ( event : string , handler : ( params : any ) => void ) : void {
142+ on ( event : string , handler : ( params : unknown ) => void ) : void {
132143 let set = this . _eventListeners . get ( event ) ;
133144 if ( ! set ) { set = new Set ( ) ; this . _eventListeners . set ( event , set ) ; }
134145 set . add ( handler ) ;
135146 }
136147
137148 /** Remove a CDP event listener */
138- off ( event : string , handler : ( params : any ) => void ) : void {
149+ off ( event : string , handler : ( params : unknown ) => void ) : void {
139150 this . _eventListeners . get ( event ) ?. delete ( handler ) ;
140151 }
141152
142153 /** Wait for a CDP event to fire (one-shot) */
143- waitForEvent ( event : string , timeoutMs : number = 15_000 ) : Promise < any > {
154+ waitForEvent ( event : string , timeoutMs : number = 15_000 ) : Promise < unknown > {
144155 return new Promise ( ( resolve , reject ) => {
145156 const timer = setTimeout ( ( ) => {
146157 this . off ( event , handler ) ;
147158 reject ( new Error ( `Timed out waiting for CDP event '${ event } '` ) ) ;
148159 } , timeoutMs ) ;
149- const handler = ( params : any ) => {
160+ const handler = ( params : unknown ) => {
150161 clearTimeout ( timer ) ;
151162 this . off ( event , handler ) ;
152163 resolve ( params ) ;
@@ -173,28 +184,29 @@ class CDPPage implements IPage {
173184 }
174185 }
175186
176- async evaluate ( js : string ) : Promise < any > {
187+ async evaluate ( js : string ) : Promise < unknown > {
177188 const expression = wrapForEval ( js ) ;
178189 const result = await this . bridge . send ( 'Runtime.evaluate' , {
179190 expression,
180191 returnByValue : true ,
181192 awaitPromise : true
182- } ) ;
193+ } ) as RuntimeEvaluateResult ;
183194 if ( result . exceptionDetails ) {
184195 throw new Error ( 'Evaluate error: ' + ( result . exceptionDetails . exception ?. description || 'Unknown exception' ) ) ;
185196 }
186197 return result . result ?. value ;
187198 }
188199
189- async getCookies ( opts : { domain ?: string ; url ?: string } = { } ) : Promise < any [ ] > {
200+ async getCookies ( opts : { domain ?: string ; url ?: string } = { } ) : Promise < BrowserCookie [ ] > {
190201 const result = await this . bridge . send ( 'Network.getCookies' , opts . url ? { urls : [ opts . url ] } : { } ) ;
191- const cookies = Array . isArray ( result ?. cookies ) ? result . cookies : [ ] ;
192- return opts . domain
193- ? cookies . filter ( ( cookie : any ) => typeof cookie . domain === 'string' && cookie . domain . includes ( opts . domain ! ) )
202+ const cookies = isRecord ( result ) && Array . isArray ( result . cookies ) ? result . cookies : [ ] ;
203+ const domain = opts . domain ;
204+ return domain
205+ ? cookies . filter ( ( cookie ) : cookie is BrowserCookie => isCookie ( cookie ) && cookie . domain . includes ( domain ) )
194206 : cookies ;
195207 }
196208
197- async snapshot ( opts : { interactive ?: boolean ; compact ?: boolean ; maxDepth ?: number ; raw ?: boolean ; viewportExpand ?: number ; maxTextLength ?: number } = { } ) : Promise < any > {
209+ async snapshot ( opts : SnapshotOptions = { } ) : Promise < unknown > {
198210 const snapshotJs = generateSnapshotJs ( {
199211 viewportExpand : opts . viewportExpand ?? 800 ,
200212 maxDepth : Math . max ( 1 , Math . min ( Number ( opts . maxDepth ) || 50 , 200 ) ) ,
@@ -220,21 +232,22 @@ class CDPPage implements IPage {
220232 await this . evaluate ( pressKeyJs ( key ) ) ;
221233 }
222234
223- async scrollTo ( ref : string ) : Promise < any > {
235+ async scrollTo ( ref : string ) : Promise < unknown > {
224236 return this . evaluate ( scrollToRefJs ( ref ) ) ;
225237 }
226238
227- async getFormState ( ) : Promise < any > {
228- return this . evaluate ( getFormStateJs ( ) ) ;
239+ async getFormState ( ) : Promise < Record < string , unknown > > {
240+ return ( await this . evaluate ( getFormStateJs ( ) ) ) as Record < string , unknown > ;
229241 }
230242
231- async wait ( options : any ) : Promise < void > {
243+ async wait ( options : number | WaitOptions ) : Promise < void > {
232244 if ( typeof options === 'number' ) {
233245 await new Promise ( resolve => setTimeout ( resolve , options * 1000 ) ) ;
234246 return ;
235247 }
236- if ( options . time ) {
237- await new Promise ( resolve => setTimeout ( resolve , options . time * 1000 ) ) ;
248+ if ( typeof options . time === 'number' ) {
249+ const waitTime = options . time ;
250+ await new Promise ( resolve => setTimeout ( resolve , waitTime * 1000 ) ) ;
238251 return ;
239252 }
240253 if ( options . text ) {
@@ -255,13 +268,13 @@ class CDPPage implements IPage {
255268 await this . evaluate ( autoScrollJs ( times , delayMs ) ) ;
256269 }
257270
258- async screenshot ( options : any = { } ) : Promise < string > {
271+ async screenshot ( options : ScreenshotOptions = { } ) : Promise < string > {
259272 const result = await this . bridge . send ( 'Page.captureScreenshot' , {
260273 format : options . format ?? 'png' ,
261274 quality : options . format === 'jpeg' ? ( options . quality ?? 80 ) : undefined ,
262275 captureBeyondViewport : options . fullPage ?? false ,
263276 } ) ;
264- const base64 = result . data ;
277+ const base64 = isRecord ( result ) && typeof result . data === 'string' ? result . data : '' ;
265278 if ( options . path ) {
266279 const fs = await import ( 'node:fs' ) ;
267280 const path = await import ( 'node:path' ) ;
@@ -272,11 +285,12 @@ class CDPPage implements IPage {
272285 return base64 ;
273286 }
274287
275- async networkRequests ( includeStatic : boolean = false ) : Promise < any > {
276- return this . evaluate ( networkRequestsJs ( includeStatic ) ) ;
288+ async networkRequests ( includeStatic : boolean = false ) : Promise < unknown [ ] > {
289+ const result = await this . evaluate ( networkRequestsJs ( includeStatic ) ) ;
290+ return Array . isArray ( result ) ? result : [ ] ;
277291 }
278292
279- async tabs ( ) : Promise < any > {
293+ async tabs ( ) : Promise < unknown [ ] > {
280294 return [ ] ;
281295 }
282296
@@ -292,7 +306,7 @@ class CDPPage implements IPage {
292306 // Not supported in direct CDP mode
293307 }
294308
295- async consoleMessages ( _level ?: string ) : Promise < any > {
309+ async consoleMessages ( _level ?: string ) : Promise < unknown [ ] > {
296310 return [ ] ;
297311 }
298312
@@ -304,13 +318,24 @@ class CDPPage implements IPage {
304318 } ) ) ;
305319 }
306320
307- async getInterceptedRequests ( ) : Promise < any [ ] > {
321+ async getInterceptedRequests ( ) : Promise < unknown [ ] > {
308322 const { generateReadInterceptedJs } = await import ( '../interceptor.js' ) ;
309323 const result = await this . evaluate ( generateReadInterceptedJs ( '__opencli_xhr' ) ) ;
310- return ( result as any [ ] ) || [ ] ;
324+ return Array . isArray ( result ) ? result : [ ] ;
311325 }
312326}
313327
328+ function isRecord ( value : unknown ) : value is Record < string , unknown > {
329+ return typeof value === 'object' && value !== null && ! Array . isArray ( value ) ;
330+ }
331+
332+ function isCookie ( value : unknown ) : value is BrowserCookie {
333+ return isRecord ( value )
334+ && typeof value . name === 'string'
335+ && typeof value . value === 'string'
336+ && typeof value . domain === 'string' ;
337+ }
338+
314339// ── CDP target selection (unchanged) ──
315340
316341function selectCDPTarget ( targets : CDPTarget [ ] ) : CDPTarget | undefined {
0 commit comments