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