1import type { DebuggerInfo, Device as MetroDevice } from 'metro-inspector-proxy';
2import type WS from 'ws';
3
4import { NetworkResponseHandler } from './handlers/NetworkResponse';
5import { VscodeCompatHandler } from './handlers/VscodeCompat';
6import { DeviceRequest, InspectorHandler, DebuggerRequest } from './handlers/types';
7
8export function createInspectorDeviceClass(MetroDeviceClass: typeof MetroDevice) {
9  return class ExpoInspectorDevice extends MetroDeviceClass implements InspectorHandler {
10    /** All handlers that should be used to intercept or reply to CDP events */
11    public handlers: InspectorHandler[] = [new NetworkResponseHandler(), new VscodeCompatHandler()];
12
13    onDeviceMessage(message: any, info: DebuggerInfo): boolean {
14      return this.handlers.some((handler) => handler.onDeviceMessage?.(message, info) ?? false);
15    }
16
17    onDebuggerMessage(message: any, info: DebuggerInfo): boolean {
18      return this.handlers.some((handler) => handler.onDebuggerMessage?.(message, info) ?? false);
19    }
20
21    /** Hook into the message life cycle to answer more complex CDP messages */
22    async _processMessageFromDevice(message: DeviceRequest<any>, info: DebuggerInfo) {
23      if (!this.onDeviceMessage(message, info)) {
24        await super._processMessageFromDevice(message, info);
25      }
26    }
27
28    /** Hook into the message life cycle to answer more complex CDP messages */
29    _interceptMessageFromDebugger(
30      request: DebuggerRequest,
31      info: DebuggerInfo,
32      socket: WS
33    ): boolean {
34      // Note, `socket` is the exact same as `info.socket`
35      if (this.onDebuggerMessage(request, info)) {
36        return true;
37      }
38
39      return super._interceptMessageFromDebugger(request, info, socket);
40    }
41  };
42}
43