1declare module 'metro-inspector-proxy/src/Device' { 2 import { Device } from 'metro-inspector-proxy'; 3 export = Device; 4} 5 6declare module 'metro-inspector-proxy' { 7 import WS from 'ws'; 8 import type { Server as HttpsServer } from 'https'; 9 import type { 10 IncomingMessage as HttpRequest, 11 ServerResponse as HttpResponse, 12 Server as HttpServer, 13 } from 'http'; 14 15 type Middleware = (error?: Error) => any; 16 17 /** 18 * Page information received from the device. New page is created for 19 * each new instance of VM and can appear when user reloads React Native 20 * application. 21 */ 22 type Page = { 23 id: string; 24 title: string; 25 vm: string; 26 app: string; 27 28 // Allow objects too 29 [key: string]: string; 30 }; 31 32 type DebuggerInfo = { 33 // Debugger web socket connection 34 socket: WS; 35 // If we replaced address (like '10.0.2.2') to localhost we need to store original 36 // address because Chrome uses URL or urlRegex params (instead of scriptId) to set breakpoints. 37 originalSourceURLAddress?: string; 38 prependedFilePrefix: boolean; 39 pageId: string; 40 41 // Allow objects too 42 [key: string]: string; 43 }; 44 45 type PageDescription = any; 46 47 function runInspectorProxy(port: number, projectRoot: string): void; 48 49 class InspectorProxy { 50 /** Root of the project used for relative to absolute source path conversion. */ 51 _projectRoot: string; 52 /** Maps device ID to Device instance. */ 53 _devices: Map<number, Device>; 54 /** Internal counter for device IDs -- just gets incremented for each new device. */ 55 _deviceCounter: number = 0; 56 57 /** 58 * We store server's address with port (like '127.0.0.1:8081') to be able to build URLs 59 * (devtoolsFrontendUrl and webSocketDebuggerUrl) for page descriptions. These URLs are used 60 * by debugger to know where to connect. 61 */ 62 _serverAddressWithPort: string = ''; 63 64 constructor(projectRoot: string); 65 66 /** 67 * Process HTTP request sent to server. We only respond to 2 HTTP requests: 68 * 1. /json/version returns Chrome debugger protocol version that we use 69 * 2. /json and /json/list returns list of page descriptions (list of inspectable apps). 70 * This list is combined from all the connected devices. 71 */ 72 processRequest(req: HttpRequest, res: HttpResponse, next: Middleware): void; 73 74 /** Adds websocket listeners to the provided HTTP/HTTPS server. */ 75 createWebSocketListeners(server: HttpServer | HttpsServer): Record<string, WS.Server>; 76 77 /** Converts page information received from device into PageDescription object that is sent to debugger. */ 78 _buildPageDescription(deviceId: number, device: Device, page: Page): PageDescription; 79 80 /** 81 * Sends object as response to HTTP request. 82 * Just serializes object using JSON and sets required headers. 83 */ 84 _sendJsonResponse(response: ServerResponse, object: any): void; 85 86 /** 87 * Adds websocket handler for device connections. 88 * Device connects to /inspector/device and passes device and app names as 89 * HTTP GET params. 90 * For each new websocket connection we parse device and app names and create 91 * new instance of Device class. 92 */ 93 _createDeviceConnectionWSServer(): WS.Server; 94 95 /** 96 * Returns websocket handler for debugger connections. 97 * Debugger connects to webSocketDebuggerUrl that we return as part of page description 98 * in /json response. 99 * When debugger connects we try to parse device and page IDs from the query and pass 100 * websocket object to corresponding Device instance. 101 */ 102 _createDebuggerConnectionWSServer(): WS.Server; 103 } 104 105 class Device { 106 /** ID of the device. */ 107 _id: number; 108 /** Name of the device. */ 109 _name: string; 110 /** Package name of the app. */ 111 _app: string; 112 /** Stores socket connection between Inspector Proxy and device. */ 113 _deviceSocket: WS; 114 /** Stores last list of device's pages. */ 115 _pages: Page[]; 116 /** Stores information about currently connected debugger (if any). */ 117 _debuggerConnection: DebuggerInfo | null = null; 118 /** Whether we are in the middle of a reload in the REACT_NATIVE_RELOADABLE_PAGE. */ 119 _isReloading: boolean = false; 120 /** The previous "GetPages" message, for deduplication in debug logs. */ 121 _lastGetPagesMessage: string = ''; 122 /** Mapping built from scriptParsed events and used to fetch file content in `Debugger.getScriptSource`. */ 123 _scriptIdToSourcePathMapping: Map<string, string>; 124 /** Root of the project used for relative to absolute source path conversion. */ 125 _projectRoot: string; 126 127 /** 128 * Last known Page ID of the React Native page. 129 * This is used by debugger connections that don't have PageID specified 130 * (and will interact with the latest React Native page). 131 */ 132 _lastConnectedReactNativePage: Page | null = null; 133 134 constructor(id: number, name: string, app: string, socket: WS, projectRoot: string); 135 136 getName(): string; 137 getPagesList(): Page[]; 138 139 /** 140 * Handles new debugger connection to this device: 141 * 1. Sends connect event to device 142 * 2. Forwards all messages from the debugger to device as wrappedEvent 143 * 3. Sends disconnect event to device when debugger connection socket closes. 144 */ 145 handleDebuggerConnection(socket: WS, pageId: string): void; 146 147 /** 148 * Handles messages received from device: 149 * 1. For getPages responses updates local _pages list. 150 * 2. All other messages are forwarded to debugger as wrappedEvent. 151 * 152 * In the future more logic will be added to this method for modifying 153 * some of the messages (like updating messages with source maps and file locations). 154 */ 155 _handleMessageFromDevice(message: MessageFromDevice): void; 156 157 /** Sends single message to device. */ 158 _sendMessageToDevice(message: MessageToDevice): void; 159 160 /** Sends 'getPages' request to device every PAGES_POLLING_INTERVAL milliseconds.*/ 161 _setPagesPolling(): void; 162 163 /** Allows to make changes in incoming message from device. */ 164 _processMessageFromDevice( 165 payload: { method: string; params: { sourceMapURL: string; url: string } }, 166 debuggerInfo: DebuggerInfo 167 ): void; 168 169 /** Allows to make changes in incoming messages from debugger. */ 170 _interceptMessageFromDebugger( 171 request: DebuggerRequest, 172 debuggerInfo: DebuggerInfo, 173 socket: WS 174 ): DebuggerResponse | null; 175 176 // _newReactNativePage 177 // _processDebuggerSetBreakpointByUrl 178 // _processDebuggerGetScriptSource 179 // _mapToDevicePageId 180 } 181} 182