Inspector proxy for React Native and dev tools integration that bridges React Native apps and Chrome DevTools.
tessl install tessl/npm-metro-inspector-proxy@0.78.0Metro Inspector Proxy is a JavaScript library that provides an inspector proxy service for React Native debugging and development tools integration. It acts as a bridge between React Native applications and Chrome DevTools or other debugging clients, enabling WebSocket connections for remote debugging, inspector protocol communication, and real-time debugging capabilities.
npm install metro-inspector-proxyconst { InspectorProxy, runInspectorProxy } = require("metro-inspector-proxy");For ES modules:
import { InspectorProxy, runInspectorProxy } from "metro-inspector-proxy";const { runInspectorProxy } = require("metro-inspector-proxy");
// Start inspector proxy server on port 8081
runInspectorProxy(8081, "/path/to/project/root");For more control, use the InspectorProxy class directly:
const { InspectorProxy } = require("metro-inspector-proxy");
const http = require("http");
const connect = require("connect");
// Create proxy instance
const inspectorProxy = new InspectorProxy("/path/to/project/root");
// Set up HTTP server with middleware
const app = connect();
app.use(inspectorProxy.processRequest.bind(inspectorProxy));
const httpServer = http.createServer(app);
httpServer.listen(8081, "127.0.0.1", () => {
// Set up WebSocket endpoints
const websocketEndpoints = inspectorProxy.createWebSocketListeners(httpServer);
httpServer.on("upgrade", (request, socket, head) => {
const { pathname } = require("url").parse(request.url);
if (pathname && websocketEndpoints[pathname]) {
websocketEndpoints[pathname].handleUpgrade(request, socket, head, (ws) => {
websocketEndpoints[pathname].emit("connection", ws, request);
});
} else {
socket.destroy();
}
});
});Metro Inspector Proxy is built around several key components:
Core proxy functionality for managing inspector connections and HTTP/WebSocket servers. Use this for creating a complete debugging server that handles device registration and debugger connections.
function runInspectorProxy(port: number, projectRoot: string): void;
class InspectorProxy {
constructor(projectRoot: string);
processRequest(
request: IncomingMessage,
response: ServerResponse,
next: (?Error) => mixed
): void;
createWebSocketListeners(
serverOrBaseUrl: HttpServer | HttpsServer | string
): { [path: string]: WS.Server };
}Device connection handling for React Native apps that connect to the proxy. Each device can have multiple inspectable pages and handles debugger session management.
class Device {
constructor(
id: string,
name: string,
app: string,
socket: WS,
projectRoot: string
);
getName(): string;
getApp(): string;
getPagesList(): Array<Page>;
handleDebuggerConnection(socket: WS, pageId: string): void;
handleDuplicateDeviceConnection(newDevice: Device): void;
}Command line tool for quickly starting an inspector proxy server with configurable options.
// CLI options
interface CLIOptions {
port: number; // -p, --port (default: 8081)
root: string; // -r, --root (default: '')
}// Page information from device
interface Page {
id: string;
title: string;
vm: string;
app: string;
}
// Page description for debugger
interface PageDescription {
id: string;
description: string;
title: string;
faviconUrl: string;
devtoolsFrontendUrl: string;
type: string;
webSocketDebuggerUrl: string;
vm: string;
deviceName: string;
}
// HTTP JSON responses
type JsonPagesListResponse = Array<PageDescription>;
interface JsonVersionResponse {
Browser: string;
'Protocol-Version': string;
}// Messages from Inspector Proxy to Device
interface ConnectRequest {
event: 'connect';
payload: { pageId: string };
}
interface DisconnectRequest {
event: 'disconnect';
payload: { pageId: string };
}
interface GetPagesRequest {
event: 'getPages';
}
interface WrappedEvent {
event: 'wrappedEvent';
payload: {
pageId: string;
wrappedEvent: string;
};
}
type MessageToDevice =
| GetPagesRequest
| WrappedEvent
| ConnectRequest
| DisconnectRequest;
// Messages from Device to Inspector Proxy
interface GetPagesResponse {
event: 'getPages';
payload: Array<Page>;
}
type MessageFromDevice =
| GetPagesResponse
| WrappedEvent
| DisconnectRequest;// Debugger request types
interface SetBreakpointByUrlRequest {
id: number;
method: 'Debugger.setBreakpointByUrl';
params: {
lineNumber: number;
url?: string;
urlRegex?: string;
scriptHash?: string;
columnNumber?: number;
condition?: string;
};
}
interface GetScriptSourceRequest {
id: number;
method: 'Debugger.getScriptSource';
params: {
scriptId: string;
};
}
interface GetScriptSourceResponse {
scriptSource: string;
bytecode?: string;
}
interface ErrorResponse {
error: {
message: string;
};
}
type DebuggerRequest = SetBreakpointByUrlRequest | GetScriptSourceRequest;
// Internal debugger connection information
interface DebuggerInfo {
socket: WS;
originalSourceURLAddress?: string;
prependedFilePrefix: boolean;
pageId: string;
}