CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-metro-inspector-proxy

Inspector proxy for React Native and dev tools integration that bridges React Native apps and Chrome DevTools.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

device-management.mddocs/

Device Management

Device connection handling for React Native apps that connect to the proxy. Each device represents a single React Native application connection and can have multiple inspectable pages (JavaScript contexts). The Device class manages debugger sessions, message forwarding, and handles Chrome DevTools Protocol communication.

Capabilities

Device Class

Represents single device connection to Inspector Proxy. Each device can have multiple inspectable pages and handles debugger session management.

/**
 * Device class represents single device connection to Inspector Proxy
 * @param id - Device ID
 * @param name - Device name
 * @param app - Package name of the app
 * @param socket - WebSocket connection to device
 * @param projectRoot - Root of the project used for relative to absolute source path conversion
 */
class Device {
  constructor(
    id: string,
    name: string,
    app: string,
    socket: WS,
    projectRoot: string
  );
  
  /**
   * Returns device name
   * @returns Device name string
   */
  getName(): string;
  
  /**
   * Returns app package name
   * @returns App package name string
   */
  getApp(): string;
  
  /**
   * Returns list of inspectable pages from this device
   * @returns Array of Page objects
   */
  getPagesList(): Array<Page>;
  
  /**
   * Handles new debugger connection to this device
   * @param socket - WebSocket connection from debugger
   * @param pageId - ID of the page to debug
   */
  handleDebuggerConnection(socket: WS, pageId: string): void;
  
  /**
   * Handles cleaning up a duplicate device connection
   * @param newDevice - New device instance attempting to connect
   */
  handleDuplicateDeviceConnection(newDevice: Device): void;
}

Usage Examples:

const Device = require("metro-inspector-proxy/src/Device");
const WebSocket = require("ws");

// Device instances are typically created automatically by InspectorProxy
// when React Native apps connect to /inspector/device WebSocket endpoint

// Example of how devices are created internally:
const deviceSocket = new WebSocket("ws://localhost:8081/inspector/device?device=myphone&name=iPhone&app=MyApp");
const device = new Device(
  "myphone",           // device ID
  "iPhone",            // device name
  "MyApp",             // app name
  deviceSocket,        // WebSocket connection
  "/path/to/project"   // project root
);

// Get device information
console.log(device.getName()); // "iPhone"
console.log(device.getApp());  // "MyApp"

// Get available pages for debugging
const pages = device.getPagesList();
console.log(pages); // Array of Page objects

Page Information

Page objects represent individual JavaScript contexts that can be debugged.

interface Page {
  id: string;      // Unique page identifier
  title: string;   // Page title (usually "React Native")
  vm: string;      // JavaScript engine name (e.g., "Hermes", "JSC")
  app: string;     // App name
}

Debugger Connection Handling

When a debugger (Chrome DevTools) connects to debug a specific page:

// Debugger connects to WebSocket endpoint with device and page IDs
const debuggerSocket = new WebSocket("ws://localhost:8081/inspector/debug?device=myphone&page=1");

// Device handles the debugger connection internally
device.handleDebuggerConnection(debuggerSocket, "1");

The Device class:

  1. Disconnects any existing debugger for this device
  2. Sets up message forwarding between debugger and device
  3. Sends connect event to the React Native app
  4. Handles Chrome DevTools Protocol message transformation

Message Processing

The Device class handles bidirectional message forwarding and transformation:

Messages from Device to Debugger

  • getPages responses: Updates local page list
  • wrappedEvent messages: Chrome DevTools Protocol messages forwarded to debugger
  • disconnect events: Handles page reloads and app disconnections

Messages from Debugger to Device

  • Chrome DevTools Protocol messages: Forwarded as wrappedEvent to device
  • Special handling for:
    • Debugger.setBreakpointByUrl: URL transformation for Android emulator addresses
    • Debugger.getScriptSource: Local file serving and HTTP source map fetching

React Native Reloadable Page

The Device class provides special handling for React Native app reloads:

// Special page ID for reloadable React Native debugging
const REACT_NATIVE_RELOADABLE_PAGE_ID = "-1";

// When available, this creates a special page entry:
{
  id: "-1",
  title: "React Native Experimental (Improved Chrome Reloads)",
  vm: "don't use",
  app: "MyApp"
}

This allows debuggers to maintain connections across React Native app reloads.

Duplicate Connection Handling

When the same device attempts to reconnect (common during app reloads):

// If same device and app reconnect
if (oldDevice.getApp() === newDevice.getApp() && 
    oldDevice.getName() === newDevice.getName()) {
  // Reuse existing debugger connection with new device socket
  olddevice.handleDuplicateDeviceConnection(newDevice);
} else {
  // Different app/device - close old connections
  oldDevice.close();
}

Source Path Resolution

The Device class handles source path resolution for debugging:

Android Emulator Address Translation

// Translates Android emulator addresses to localhost for Chrome DevTools
const EMULATOR_LOCALHOST_ADDRESSES = ["10.0.2.2", "10.0.3.2"];

// Example: "http://10.0.2.2:8081/bundle.js" becomes "http://localhost:8081/bundle.js"

File URL Handling

// Adds file:// prefix to alphanumeric script IDs for Chrome DevTools compatibility
const FILE_PREFIX = "file://";

// Example: "12abc34" becomes "file://12abc34"

Source Map Processing

  • Fetches HTTP-based source maps and converts to data URLs
  • Handles local file reading for source content
  • Maintains script ID to source path mapping for Debugger.getScriptSource requests

Error Handling

The Device class provides error handling and debugging support:

/**
 * Sends error message to connected debugger console
 * @param message - Error message to display in debugger console
 */
_sendErrorToDebugger(message: string): void;

/**
 * Sends message to connected device
 * @param message - Message to send to device
 */
_sendMessageToDevice(message: MessageToDevice): void;

/**
 * Processes message from device, handling special cases like getPages and wrappedEvent
 * @param message - Message received from device
 */
_handleMessageFromDevice(message: MessageFromDevice): void;

/**
 * Processes messages from device with source path transformation
 * @param payload - Message payload with method and params
 * @param debuggerInfo - Information about current debugger connection
 */
_processMessageFromDevice(
  payload: { method: string, params: { sourceMapURL: string, url: string } },
  debuggerInfo: DebuggerInfo
): Promise<void>;

/**
 * Intercepts and processes messages from debugger before forwarding to device
 * @param req - Debugger request
 * @param debuggerInfo - Information about current debugger connection  
 * @param socket - WebSocket connection to debugger
 * @returns Whether message was handled locally (true) or should be forwarded (false)
 */
_interceptMessageFromDebugger(
  req: DebuggerRequest,
  debuggerInfo: DebuggerInfo,
  socket: WS
): boolean;

Errors are sent to the debugger as Runtime.consoleAPICalled events with type 'error', appearing in the Chrome DevTools console.

docs

cli-interface.md

device-management.md

index.md

inspector-proxy.md

tile.json