### Set up LIFF Inspector for Development Source: https://github.com/line/liff-inspector/blob/main/CONTRIBUTING.md Clone the repository and install dependencies to start developing. Ensure you have the correct Node.js version managed by nvm. ```bash git clone git@github.com:line/liff-inspector.git cd liff-inspector nvm use npm install ``` -------------------------------- ### Start LIFF Inspector Server (CLI) Source: https://context7.com/line/liff-inspector/llms.txt Use these CLI commands to start the LIFF Inspector server. Supports both HTTP and HTTPS configurations. Ensure you have the necessary key and certificate files for HTTPS. ```bash npx @line/headless-inspector --https ``` ```bash npx @line/headless-inspector --key=path/to/key.pem --cert=path/to/cert.pem ``` -------------------------------- ### Start LIFF Inspector Server Source: https://github.com/line/liff-inspector/blob/main/packages/liff-inspector/README.md Run this command in your terminal to start the LIFF Inspector server. It will listen for connections on a specific port. ```sh npx @line/liff-inspector Debugger listening on ws://{IP Address}:9222 ``` -------------------------------- ### Start Generic Headless Browser Relay Server (CLI) Source: https://context7.com/line/liff-inspector/llms.txt Starts a standalone relay server for non-LIFF web pages. Inject `headless-inspector.js` into your HTML to enable remote DevTools inspection without framework dependencies. ```bash # Start server npx @line/headless-inspector ``` -------------------------------- ### Serve Headless Inspector Locally Source: https://github.com/line/liff-inspector/blob/main/packages/headless-inspector/README.md Run the headless-inspector command to start a local server. Use the --https flag for HTTPS or specify key and cert paths. If no flags are used, it serves over HTTP. ```sh # serve https:// $ npx @line/headless-inspector --https $ npx @line/headless-inspector --key=path/to/key.pem --cert=/path/to/cert.pem # serve http:// $ npx @line/headless-inspector ``` -------------------------------- ### Start LIFF Inspector Server Source: https://github.com/line/liff-inspector/blob/main/README.md Run this command in your terminal to start the LIFF Inspector server. It will listen on ws://{IP Address}:9222. ```sh npx @line/liff-inspector ``` -------------------------------- ### Start LIFF Inspector Relay Server (CLI) Source: https://context7.com/line/liff-inspector/llms.txt Starts the headless inspector relay server on port 9222. Use `--https` for auto-generated certificates or provide your own with `--key` and `--cert`. The server prints a `devtools://` URL upon client connection. ```bash # Start HTTP server (local only, not suitable for LIFF over HTTPS) npx @line/liff-inspector # Debugger listening on ws://192.168.1.5:9222 # You need to serve this server over SSL/TLS # Start with auto-generated self-signed HTTPS certificate npx @line/liff-inspector --https # Debugger listening on wss://192.168.1.5:9222 # Start with your own certificates (e.g., from mkcert) npx @line/liff-inspector --key=localhost-key.pem --cert=localhost.pem # Debugger listening on wss://192.168.1.5:9222 # After a LIFF app connects, the server prints: # connection from client, id: liff-1234567890-AbCdEf # DevTools URL: devtools://devtools/bundled/inspector.html?wss=abc-def.ngrok.io/?hi_id=liff-1234567890-AbCdEf ``` -------------------------------- ### Install LIFF Inspector Plugin Source: https://github.com/line/liff-inspector/blob/main/README.md Install the LIFF Inspector plugin using npm. This is required to integrate the inspector into your LIFF app. ```sh npm install @line/liff-inspector ``` -------------------------------- ### runServer Source: https://context7.com/line/liff-inspector/llms.txt Programmatically starts the Express + WebSocket server for the LIFF Inspector. This server serves the injectable script bundle and relays CDP messages. ```APIDOC ## `runServer` — Programmatic Server Startup The underlying server factory function exported from `@line/headless-inspector`. Creates an Express + WebSocket server that serves the injectable script bundle and relays CDP messages between DevTools and client connections. ```ts import { runServer, getPrivateIp, parseArgv } from '@line/headless-inspector/dist/server'; const privateIp = getPrivateIp(); // e.g., "192.168.1.10" const { ssl } = parseArgv(process.argv); runServer( { port: 9222, ssl, // undefined for HTTP, or { key: Buffer, cert: Buffer } for HTTPS devInfo: { description: 'my-custom-inspector', devtoolsFrontendUrl: `http://${privateIp}:9222`, id: process.pid, title: 'My App', type: 'page', url: '', webSocketDebuggerUrl: `ws://${privateIp}:9222/my-inspector`, }, }, () => { console.log(`Server listening on port 9222`); } ); // GET /json and GET /json/list return the devInfo for Chrome DevTools discovery // WebSocket connections are automatically routed by hi_id ``` ``` -------------------------------- ### Programmatic Server Startup with runServer Source: https://context7.com/line/liff-inspector/llms.txt Use the `runServer` function to programmatically start the Express + WebSocket server. Configure port, SSL, and developer information. The server serves the script bundle and relays CDP messages. ```typescript import { runServer, getPrivateIp, parseArgv } from '@line/headless-inspector/dist/server'; const privateIp = getPrivateIp(); // e.g., "192.168.1.10" const { ssl } = parseArgv(process.argv); runServer( { port: 9222, ssl, devInfo: { description: 'my-custom-inspector', devtoolsFrontendUrl: `http://${privateIp}:9222`, id: process.pid, title: 'My App', type: 'page', url: '', webSocketDebuggerUrl: `ws://${privateIp}:9222/my-inspector`, }, }, () => { console.log(`Server listening on port 9222`); } ); // GET /json and GET /json/list return the devInfo for Chrome DevTools discovery // WebSocket connections are automatically routed by hi_id ``` -------------------------------- ### Initialize and Enable HeadlessInspectorClient Source: https://context7.com/line/liff-inspector/llms.txt Instantiate `HeadlessInspectorClient` with a CDP implementation to manage WebSocket connections. Call `enable` with the server URL to start interception and message relay. Use `disable` to stop. ```typescript import { HeadlessInspectorClient } from '@line/headless-inspector/dist/client'; import HeadlessInspectorCdp from '@line/headless-inspector-cdp'; const cdp = new HeadlessInspectorCdp(); const client = new HeadlessInspectorClient(cdp); // Connect to relay server — starts interception and bidirectional message relay client.enable('wss://my-server.ngrok.io/?hi_id=session-abc'); // When DevTools sends "Runtime.getProperties", the client: // 1. Receives: { id: 1, method: "Runtime.getProperties", params: { objectId: "obj-123" } } // 2. Calls: cdp.send("Runtime.getProperties", { objectId: "obj-123" }) // 3. Responds: { id: 1, method: "Runtime.getProperties", result: { ... } } // To stop interception: client.disable(); ``` -------------------------------- ### Serve LIFF Inspector Server over HTTPS with ngrok Source: https://github.com/line/liff-inspector/blob/main/README.md To avoid mixed content issues, serve the LIFF Inspector server over HTTPS. This example shows how to use ngrok to create a public HTTPS URL for your local server. ```sh $ ngrok http 9222 ``` ```sh $ node -e "const res=$(curl -s -sS http://127.0.0.1:4040/api/tunnels); const url=new URL(res.tunnels[0].public_url); console.log('wss://'+url.host);" ``` -------------------------------- ### LIFF Inspector Server Output with DevTools URL Source: https://github.com/line/liff-inspector/blob/main/README.md When the LIFF Inspector server is running and a client connects, it will output a DevTools URL. Open this URL in your browser to start debugging. ```diff $ npx @line/liff-inspector Debugger listening on ws://{IP Address}:9222 + connection from client, id: xxx + DevTools URL: devtools://devtools/bundled/inspector.html?wss=8a6f-113-35-87-12.ngrok.io/?hi_id=xxx ``` -------------------------------- ### npx @line/liff-inspector Source: https://context7.com/line/liff-inspector/llms.txt Starts the headless inspector relay server on port `9222`. The server accepts WebSocket connections from both LIFF Inspector Plugin clients and Chrome DevTools, routing messages between the two by matching on `hi_id`. When a LIFF app connects, the server prints a `devtools://` URL to the console. ```APIDOC ## npx @line/liff-inspector ### Description Starts the headless inspector relay server on port `9222`. The server accepts WebSocket connections from both LIFF Inspector Plugin clients and Chrome DevTools, routing messages between the two by matching on `hi_id`. When a LIFF app connects, the server prints a `devtools://` URL to the console. ### Usage ```sh # Start HTTP server (local only, not suitable for LIFF over HTTPS) npx @line/liff-inspector # Debugger listening on ws://192.168.1.5:9222 # You need to serve this server over SSL/TLS # Start with auto-generated self-signed HTTPS certificate npx @line/liff-inspector --https # Debugger listening on wss://192.168.1.5:9222 # Start with your own certificates (e.g., from mkcert) npx @line/liff-inspector --key=localhost-key.pem --cert=localhost.pem # Debugger listening on wss://192.168.1.5:9222 # After a LIFF app connects, the server prints: # connection from client, id: liff-1234567890-AbCdEf # DevTools URL: devtools://devtools/bundled/inspector.html?wss=abc-def.ngrok.io/?hi_id=liff-1234567890-AbCdEf ``` ### Options - `--https` - Use auto-generated self-signed HTTPS certificate. - `--key ` - Path to the private key file for HTTPS. - `--cert ` - Path to the certificate file for HTTPS. ``` -------------------------------- ### npx @line/headless-inspector Source: https://context7.com/line/liff-inspector/llms.txt A standalone relay server variant for non-LIFF web pages. After starting, inject `headless-inspector.js` via a ` ``` -------------------------------- ### Listen to Console API Calls with Headless Inspector Source: https://github.com/line/liff-inspector/blob/main/packages/headless-inspector-core/README.md Instantiate the HeadlessInspector, enable it, and subscribe to the 'consoleAPIHasBeenCalled' event to receive details about console method invocations. ```typescript import HeadlessInspector from '@line/headless-inspector-core'; const inspector = new HeadlessInspector(); inspector.on( 'consoleAPIHasBeenCalled', ({ argumentsList, type, timestamp }) => { // argumentsList: ["hoge"] // type: "log" } ); inspector.enable(); console.log('hoge'); ``` -------------------------------- ### Basic LIFF Inspector Plugin Usage Source: https://context7.com/line/liff-inspector/llms.txt Integrate the LIFFInspectorPlugin into your LIFF app to enable remote debugging. It automatically connects to the relay server before LIFF SDK initialization. Use a custom origin for HTTPS environments. ```typescript import liff from '@line/liff'; import LIFFInspectorPlugin from '@line/liff-inspector'; // Basic usage — connects to ws://localhost:9222 by default liff.use(new LIFFInspectorPlugin()); // With a custom origin (required when LIFF app is served over HTTPS) liff.use(new LIFFInspectorPlugin({ origin: 'wss://xxxx-xxx-xxx.ngrok.io' })); liff.init({ liffId: 'liff-xxxxxxxxxx' }).then(() => { // LIFF Inspector is already connected and active at this point console.log('App initialized'); // This log appears in Chrome DevTools Console tab }); ``` -------------------------------- ### getOriginFromUrl Source: https://context7.com/line/liff-inspector/llms.txt Reads the `li.origin` query parameter from the page's search string to allow dynamic server origin configuration without code changes. Takes precedence over the `origin` constructor option. ```APIDOC ## getOriginFromUrl ### Description Reads the `li.origin` query parameter from the page's search string to allow dynamic server origin configuration without code changes. Takes precedence over the `origin` constructor option. ### Usage ```ts import { getOriginFromUrl } from '@line/liff-inspector'; // URL: https://liff.line.me/liff-xxx?li.origin=wss%3A%2F%2Fmy-server.ngrok.io const origin = getOriginFromUrl(window.location.search); console.log(origin); // "wss://my-server.ngrok.io" // Origin resolution priority (pseudo-code mirroring plugin internals): const originFromURL = getOriginFromUrl(window.location.search); // highest priority const originFromConfig = pluginOption?.origin; // second priority const defaultOrigin = 'wss://localhost:9222'; // fallback const resolvedOrigin = originFromURL ?? originFromConfig ?? defaultOrigin; ``` ### Parameters - **searchString** (string) - Required - The search string from `window.location.search`. ``` -------------------------------- ### Bidirectional ID/Value Map (`Store`) Source: https://context7.com/line/liff-inspector/llms.txt The `Store` class provides a generic bidirectional map for associating numeric IDs with DOM nodes or string IDs with response bodies. It supports lookups in both directions. ```typescript import { Store } from '@line/headless-inspector-cdp/src/store/Store'; const nodeStore = new Store(); const divNode = document.createElement('div'); nodeStore.store(101, divNode); nodeStore.getById(101); // → divNode (HTMLDivElement) nodeStore.getByValue(divNode); // → 101 // Used in DOM events to map CDP nodeIds → actual DOM nodes: // setCommandHandler('Overlay.highlightNode', ({ nodeId }) => { // const node = nodeStore.getById(nodeId); // retrieve real DOM node // highlight.show(node, config); // }); ``` -------------------------------- ### Configure LIFF Inspector Plugin with HTTPS Origin Source: https://github.com/line/liff-inspector/blob/main/README.md If your LIFF Inspector Server is served over HTTPS (e.g., via ngrok), you can specify the origin URL using the `origin` configuration option when initializing the plugin. ```ts // Default origin: ws://localhost:9222 liff.use(new LIFFInspectorPlugin({ origin: 'wss://xxx-xx-xx-xx.ngrok.io' })); ``` -------------------------------- ### Build WebSocket Connection URL Source: https://context7.com/line/liff-inspector/llms.txt Constructs the WebSocket URL for connecting the LIFF Inspector Plugin to the relay server. The `liffId` is used as the session identifier (`hi_id`). Handles trailing slashes in the origin URL automatically. ```typescript import { getBackendUrl } from '@line/liff-inspector'; const url = getBackendUrl('liff-1234567890-AbCdEf', 'wss://abc-def.ngrok.io'); console.log(url); // "wss://abc-def.ngrok.io/?hi_id=liff-1234567890-AbCdEf" // Trailing slash in origin is handled automatically: const url2 = getBackendUrl('liff-xxx', 'wss://server.ngrok.io/'); console.log(url2); // "wss://server.ngrok.io/?hi_id=liff-xxx" ``` -------------------------------- ### Typed Event Emitter Factory (`evemitter`) Source: https://context7.com/line/liff-inspector/llms.txt Use `evemitter` for type-safe event handling with per-event listeners and a catch-all handler. It includes protection against infinite emit loops. ```typescript import { evemitter } from '@line/headless-inspector-core'; type MyEvents = { userLogin: { userId: number; username: string }; pageView: { path: string; timestamp: number }; }; const emitter = evemitter(); // Per-event listener emitter.on('userLogin', ({ userId, username }) => { console.log(`User ${username} (${userId}) logged in`); }); // Catch-all listener — receives every event emitter.onAll((key, value) => { console.log(`Event "${String(key)}":`, value); }); emitter.emit('userLogin', { userId: 42, username: 'Alice' }); // → "User Alice (42) logged in" // → Event "userLogin": { userId: 42, username: 'Alice' } emitter.emit('pageView', { path: '/home', timestamp: Date.now() }); // → Event "pageView": { path: '/home', timestamp: 1714000000000 } ``` -------------------------------- ### Intercept Console Logs with interceptConsole Source: https://context7.com/line/liff-inspector/llms.txt Replace console methods with proxies that emit 'consoleAPIHasBeenCalled' events. This preserves original behavior while allowing for remote logging or file output. ```typescript import { interceptConsole } from '@line/headless-inspector-core'; import { evemitter } from '@line/headless-inspector-core'; import { DebugEventMap } from '@line/headless-inspector-core'; const emitter = evemitter(); emitter.on('consoleAPIHasBeenCalled', ({ type, argumentsList, timestamp }) => { // Forward to remote DevTools or log to file sendToDevTools({ event: 'console', type, args: argumentsList, timestamp }); }); interceptConsole(emitter); // Now these are transparently intercepted: console.log('User logged in', { userId: 42 }); // → emits: { type: 'log', argumentsList: ['User logged in', { userId: 42 }], timestamp: ... } console.warn('Deprecated API call'); // → emits: { type: 'warn', argumentsList: ['Deprecated API call'], timestamp: ... } console.error(new Error('Something went wrong')); // → emits: { type: 'error', argumentsList: [Error], timestamp: ... } ``` -------------------------------- ### Include Inspector Script in HTML Source: https://context7.com/line/liff-inspector/llms.txt Add this script tag to your HTML page to enable the headless inspector. You can use a fixed session ID to reconnect to the same DevTools window. ```html ``` ```html ``` -------------------------------- ### HeadlessInspectorClient Source: https://context7.com/line/liff-inspector/llms.txt Manages the WebSocket connection between the browser-side inspector and the relay server. It enables interception and relays CDP messages. ```APIDOC ## `HeadlessInspectorClient` — WebSocket Client Bridge Manages the WebSocket connection between the browser-side inspector and the relay server. On connection open it calls `inspector.enable()` to start intercepting browser APIs; all CDP events emitted by the inspector are serialized and forwarded to the server, and all commands from DevTools are dispatched to the inspector's command handler. ```ts import { HeadlessInspectorClient } from '@line/headless-inspector/dist/client'; import HeadlessInspectorCdp from '@line/headless-inspector-cdp'; const cdp = new HeadlessInspectorCdp(); const client = new HeadlessInspectorClient(cdp); // Connect to relay server — starts interception and bidirectional message relay client.enable('wss://my-server.ngrok.io/?hi_id=session-abc'); // When DevTools sends "Runtime.getProperties", the client: // 1. Receives: { id: 1, method: "Runtime.getProperties", params: { objectId: "obj-123" } } // 2. Calls: cdp.send("Runtime.getProperties", { objectId: "obj-123" }) // 3. Responds: { id: 1, method: "Runtime.getProperties", result: { ... } } // To stop interception: client.disable(); ``` ``` -------------------------------- ### getBackendUrl Source: https://context7.com/line/liff-inspector/llms.txt Constructs the WebSocket URL used to connect the LIFF Inspector Plugin to the relay server. The `liffId` is used as the `hi_id` session identifier so that Chrome DevTools can be matched to the correct client connection. ```APIDOC ## getBackendUrl ### Description Constructs the WebSocket URL used to connect the LIFF Inspector Plugin to the relay server. The `liffId` is used as the `hi_id` session identifier so that Chrome DevTools can be matched to the correct client connection. ### Usage ```ts import { getBackendUrl } from '@line/liff-inspector'; const url = getBackendUrl('liff-1234567890-AbCdEf', 'wss://abc-def.ngrok.io'); console.log(url); // "wss://abc-def.ngrok.io/?hi_id=liff-1234567890-AbCdEf" // Trailing slash in origin is handled automatically: const url2 = getBackendUrl('liff-xxx', 'wss://server.ngrok.io/'); console.log(url2); // "wss://server.ngrok.io/?hi_id=liff-xxx" ``` ### Parameters - **liffId** (string) - Required - The LIFF ID of the application. - **origin** (string) - Required - The base WebSocket origin URL. ``` -------------------------------- ### DOM Element Overlay (`Highlight`) Source: https://context7.com/line/liff-inspector/llms.txt The `Highlight` class renders an overlay on DOM elements identified by `nodeId`. It's used for hover effects in tools like Chrome DevTools Elements tab. ```typescript import { Highlight } from '@line/headless-inspector-cdp/src/highlight'; const highlight = new Highlight((el) => document.body.appendChild(el)); // Show a blue highlight over a target element const targetElement = document.querySelector('#my-button')!; highlight.show(targetElement, { contentColor: 'rgba(111,168,220,0.66)' }); // Hide the highlight highlight.hide(); // In CDP context, Overlay commands trigger this automatically: // DevTools sends: { method: "Overlay.highlightNode", params: { nodeId: 42, highlightConfig: { contentColor: { r:111, g:168, b:220, a:0.66 } } } } // → Calls highlight.show(nodeStore.getById(42), { contentColor: "rgba(111,168,220,0.66)" }) // DevTools sends: { method: "Overlay.hideHighlight", params: {} } // → Calls highlight.hide() ``` -------------------------------- ### Core Interception with HeadlessInspector Source: https://context7.com/line/liff-inspector/llms.txt Use the `HeadlessInspector` class to manage event interception for console, network, and other browser APIs. Listen to specific events or use `onAll` for a catch-all. Activate interceptors with `enable()` and send CDP commands. ```typescript import HeadlessInspector from '@line/headless-inspector-core'; const inspector = new HeadlessInspector(); // Listen to specific debug events inspector.on('consoleAPIHasBeenCalled', ({ type, argumentsList, timestamp }) => { console.log(`[${type}] at ${timestamp}:`, argumentsList); // e.g., [log] at 1714000000000: ["Hello", { user: "Alice" }] }); inspector.on('networkRequestHasBeenMade', ({ type, requestId, request }) => { console.log(`${type.toUpperCase()} ${request.method} ${request.url}`); // e.g., FETCH GET https://api.example.com/users }); inspector.on('networkRequestHasSucceeded', ({ requestId, response }) => { console.log(`Response ${response.statusCode} for ${response.url}`); }); // Attach a catch-all listener (used internally by HeadlessInspectorClient) inspector.onAll((eventName, data) => { console.log(`Event: ${String(eventName)}`, data); }); // Activate interceptors (idempotent — safe to call multiple times) inspector.enable(); // Send a CDP-style command (currently supports 'getRootNode') const rootNode = inspector.send('getRootNode', undefined); console.log(rootNode); // returns window.document.getRootNode() ``` -------------------------------- ### Intercept Network Requests with interceptNetwork Source: https://context7.com/line/liff-inspector/llms.txt Wrap window.fetch and XMLHttpRequest to emit 'networkRequestHasBeenMade' and 'networkRequestHasSucceeded' events. Original responses are unmodified. ```typescript import { interceptNetwork } from '@line/headless-inspector-core'; import { evemitter } from '@line/headless-inspector-core'; import { DebugEventMap } from '@line/headless-inspector-core'; const emitter = evemitter(); emitter.on('networkRequestHasBeenMade', ({ type, requestId, request, timestamp }) => { console.log(`[${type}] → ${request.method} ${request.url} (id: ${requestId})`); // [fetch] → POST https://api.example.com/data (id: k7f3m2x1p) }); emitter.on('networkRequestHasSucceeded', ({ type, requestId, response }) => { console.log(`[${type}] ← ${response.statusCode} ${response.url} — ${response.text.length} bytes`); // [fetch] ← 200 https://api.example.com/data — 342 bytes }); interceptNetwork(emitter); // Intercepted transparently — original behavior preserved: fetch('https://api.example.com/data', { method: 'POST', body: JSON.stringify({ key: 'val' }) }); const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://api.example.com/users'); xhr.send(); ``` -------------------------------- ### Convert Node to CDP-Compatible DOM Node Source: https://context7.com/line/liff-inspector/llms.txt Converts a native Node or ChildNode into a Protocol.DOM.Node-compatible object. Attributes are serialized as a flat [name, value, name, value, ...] array. Use this to prepare DOM nodes for transmission to Chrome DevTools. ```typescript import { CDPNode, getAttributes } from '@line/headless-inspector-cdp/src/objects/dom/Node'; const divEl = document.createElement('div'); divEl.setAttribute('class', 'container'); divEl.setAttribute('id', 'main'); const cdpNode = new CDPNode({ nodeId: 42, parentId: 1, node: divEl, childNodeCount: 3, }); console.log(cdpNode.nodeId); // 42 console.log(cdpNode.nodeName); // "DIV" console.log(cdpNode.localName); // "div" console.log(cdpNode.nodeType); // 1 (Node.ELEMENT_NODE) console.log(cdpNode.attributes); // ["class", "container", "id", "main"] — flat alternating name/value pairs // With children resolved: const withChildren = new CDPNode({ nodeId: 43, node: document.body, children: [cdpNode], }); console.log(withChildren.childNodeCount); // 1 console.log(withChildren.children); // [cdpNode] ``` -------------------------------- ### HeadlessInspector Source: https://context7.com/line/liff-inspector/llms.txt The core interception engine that manages event interception for console APIs, network requests, and more. It uses Proxy-based interceptors. ```APIDOC ## `HeadlessInspector` — Core Interception Engine The core class in `@line/headless-inspector-core` that manages event interception. Calling `enable()` installs Proxy-based interceptors over `console.log/warn/error/info`, `window.fetch`, and `XMLHttpRequest`. Intercepted events are emitted via a typed event emitter. ```ts import HeadlessInspector from '@line/headless-inspector-core'; const inspector = new HeadlessInspector(); // Listen to specific debug events inspector.on('consoleAPIHasBeenCalled', ({ type, argumentsList, timestamp }) => { console.log(`[${type}] at ${timestamp}:`, argumentsList); // e.g., [log] at 1714000000000: ["Hello", { user: "Alice" }] }); inspector.on('networkRequestHasBeenMade', ({ type, requestId, request }) => { console.log(`${type.toUpperCase()} ${request.method} ${request.url}`); // e.g., FETCH GET https://api.example.com/users }); inspector.on('networkRequestHasSucceeded', ({ requestId, response }) => { console.log(`Response ${response.statusCode} for ${response.url}`); }); // Attach a catch-all listener (used internally by HeadlessInspectorClient) inspector.onAll((eventName, data) => { console.log(`Event: ${String(eventName)}`, data); }); // Activate interceptors (idempotent — safe to call multiple times) inspector.enable(); // Send a CDP-style command (currently supports 'getRootNode') const rootNode = inspector.send('getRootNode', undefined); console.log(rootNode); // returns window.document.getRootNode() ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.