### What does this PR do? - Bumps some packages - Does some _best practices_ in certain areas to minimize Aikido noise. ### How did you verify your code works? CI. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
bun-inspector-protocol
bun-inspector-protocol is a TypeScript library that provides a comprehensive interface for interacting with the WebKit Inspector Protocol. This package makes it easy to build debugging tools, IDE integrations, and other developer tools that communicate with Bun's JavaScript runtime.
You can use this library with Node.js or Bun.
Overview
The WebKit Inspector Protocol is a JSON-based protocol similar to the Chrome DevTools Protocol. It allows external tools to interact with Bun's JavaScript runtime for debugging, profiling, and instrumentation purposes.
Features
- 🌐 WebSocket communication: Connect to Bun's debugging endpoint via WebSockets
- 🔌 Socket communication: Connect via Unix/TCP sockets for local debugging
- 🔄 Full API typing: Complete TypeScript definitions for the protocol
- 📊 Object preview utilities: Format runtime objects for display
- 🔄 Event-driven architecture: Subscribe to specific debugging events
- 🧩 Promise-based API: Clean, modern async interface
Installation
bun add bun-inspector-protocol
# npm install bun-inspector-protocol
# yarn add bun-inspector-protocol
# pnpm add bun-inspector-protocol
Basic Usage
The first step is to spawn a Bun process with the inspector attached. There are a few different ways to do this.
The --inspect-wait flag is the easiest way to spawn a Bun process with the inspector attached.
bun --inspect-wait my-script.ts
From there, it will start a WebSocket server defaulting to port 9229 and you will need to read the output from stdout to get the URL of the inspector:
bun --inspect-wait my-script.ts 2>&1 | grep -o '\sws://.*$'
From there, you can connect to the inspector using the WebSocketInspector class:
import { WebSocketInspector } from "bun-inspector-protocol";
// Create a new inspector client
const inspector = new WebSocketInspector("ws://localhost:9229/ws");
Connecting via WebSocket
import { WebSocketInspector } from "bun-inspector-protocol";
// Create a new inspector client
const inspector = new WebSocketInspector("ws://localhost:9229/ws");
// Listen for connection events
inspector.on("Inspector.connected", () => {
console.log("Connected to debugger!");
});
inspector.on("Inspector.error", error => {
console.error("Inspector error:", error);
});
// Connect to the debugger
await inspector.start();
// Enable the Runtime domain
await inspector.send("Runtime.enable");
// Execute some code in the target context
const result = await inspector.send("Runtime.evaluate", {
expression: "2 + 2",
returnByValue: true,
});
console.log("Evaluation result:", result.result.value); // 4
// Close the connection
inspector.close();
Connecting via Socket (for Local Debugging)
import { NodeSocketInspector } from "bun-inspector-protocol";
import { Socket } from "node:net";
// Create a socket connection
const socket = new Socket();
socket.connect("/path/to/debug/socket");
// Create a new inspector client
const inspector = new NodeSocketInspector(socket);
// Set up event listeners and use the API as with WebSocketInspector
inspector.on("Inspector.connected", () => {
console.log("Connected to debugger via socket!");
});
await inspector.start();
// Use the same API as WebSocketInspector from here...
Event Handling
The inspector emits various events you can listen for:
// Listen for specific protocol events
inspector.on("Debugger.scriptParsed", params => {
console.log("Script parsed:", params.url);
});
// Listen for breakpoint hits
inspector.on("Debugger.paused", params => {
console.log("Execution paused at:", params.callFrames[0].location);
});
// Listen for console messages
inspector.on("Runtime.consoleAPICalled", params => {
console.log(
"Console message:",
params.args
.map(arg =>
// Use the included utility to format objects
remoteObjectToString(arg, true),
)
.join(" "),
);
});
Protocol Domains
The WebKit Inspector Protocol is organized into domains that group related functionality. Based on the JavaScriptCore protocol implementation, the following domains are available:
Console Domain
- Console message capturing and monitoring
- Support for different logging channels and levels (xml, javascript, network, etc.)
- Methods:
enable,disable,clearMessages,setLoggingChannelLevel, etc. - Events:
messageAdded,messageRepeatCountUpdated,messagesCleared
Debugger Domain
- Comprehensive debugging capabilities
- Setting and managing breakpoints (conditional, URL-based, symbolic)
- Execution control (pause, resume, step, etc.)
- Stack frame inspection and manipulation
- Methods:
enable,setBreakpoint,resume,stepInto,evaluateOnCallFrame, etc. - Events:
scriptParsed,breakpointResolved,paused,resumed
Heap Domain
- Memory management and garbage collection monitoring
- Heap snapshot creation and analysis
- Memory leak detection with tracking
- Methods:
enable,gc,snapshot,startTracking,stopTracking - Events:
garbageCollected,trackingStart,trackingComplete
Inspector Domain
- Core inspector functionality
- Methods:
enable,disable,initialized - Events:
evaluateForTestInFrontend,inspect
LifecycleReporter Domain
- Process lifecycle management
- Error reporting
- Methods:
enable,preventExit,stopPreventingExit - Events:
reload,error
Runtime Domain
- JavaScript runtime interaction
- Expression evaluation
- Object property inspection
- Promise handling
- Type profiling and control flow analysis
- Methods:
evaluate,callFunctionOn,getProperties,awaitPromise, etc. - Events:
executionContextCreated
ScriptProfiler Domain
- Script execution profiling
- Performance tracking
- Methods:
startTracking,stopTracking - Events:
trackingStart,trackingUpdate,trackingComplete
TestReporter Domain
- Test execution monitoring
- Test status reporting (pass, fail, timeout, skip, todo)
- Methods:
enable,disable - Events:
found,start,end
Each domain has its own set of commands, events, and data types. Refer to the TypeScript definitions in this package for complete API details.
Working with Remote Objects
When evaluating expressions, you'll often receive remote object references. Use the remoteObjectToString utility to convert these to string representations:
import { remoteObjectToString } from "bun-inspector-protocol";
const result = await inspector.send("Runtime.evaluate", {
expression: "{ a: 1, b: { c: 'hello' } }",
});
console.log(remoteObjectToString(result.result, true));
// Output: {a: 1, b: {c: "hello"}}
Message Structure
The protocol uses a simple JSON-based message format:
Requests
interface Request<T> {
id: number; // Unique request identifier
method: string; // Domain.method name format
params: T; // Method-specific parameters
}
Responses
interface Response<T> {
id: number; // Matching request identifier
result?: T; // Method-specific result (on success)
error?: {
// Error information (on failure)
code?: string;
message: string;
};
}
Events
interface Event<T> {
method: string; // Domain.event name format
params: T; // Event-specific parameters
}
Setting Breakpoints
// Set a breakpoint by URL
const { breakpointId } = await inspector.send("Debugger.setBreakpointByUrl", {
lineNumber: 42,
url: "/app/foo.ts",
condition: "x > 5", // Optional condition
});
// Set a breakpoint with custom actions
await inspector.send("Debugger.setBreakpoint", {
location: { scriptId: "123", lineNumber: 10 },
options: {
condition: "count > 5",
actions: [
{ type: "log", data: "Breakpoint hit!" },
{ type: "evaluate", data: "console.log('Custom breakpoint action')" },
],
autoContinue: true,
},
});
// Remove a breakpoint
await inspector.send("Debugger.removeBreakpoint", { breakpointId });
Memory Profiling
// Start heap tracking
await inspector.send("Heap.enable");
await inspector.send("Heap.startTracking");
// Listen for GC events
inspector.on("Heap.garbageCollected", ({ collection }) => {
console.log(
`GC completed: ${collection.type} (${collection.endTime - collection.startTime}ms)`,
);
});
// ... perform operations to analyze ...
// Get heap snapshot
const { snapshotData } = await inspector.send("Heap.stopTracking");
// Process snapshotData to find memory leaks
Script Profiling
// Start script profiling with sampling
await inspector.send("ScriptProfiler.startTracking", { includeSamples: true });
// Listen for profiling updates
inspector.on("ScriptProfiler.trackingUpdate", event => {
console.log("Profiling event:", event);
});
// Stop profiling to get complete data
inspector.on("ScriptProfiler.trackingComplete", data => {
if (data.samples) {
// Process stack traces
console.log(`Collected ${data.samples.stackTraces.length} stack traces`);
}
});
await inspector.send("ScriptProfiler.stopTracking");
Protocol Differences from Upstream WebKit
Notable Bun-specific additions include:
LifecycleReporterdomain for process lifecycle management- Enhanced
TestReporterdomain for test framework integration - Additional utilities for script and heap profiling
Building Tools with the Protocol
This library is ideal for building:
- IDE extensions and debuggers
- Performance monitoring tools
- Testing frameworks with runtime instrumentation
- Hot module reloading systems
- Custom REPL environments
- Profiling and optimization tools
Full API Reference
For complete API documentation, please refer to the TypeScript definitions included in this package. The definitions provide comprehensive information about all available commands, events, and their parameters.
License
MIT