npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

electron-cdp-utils

v0.4.2

Published

A powerful TypeScript library that simplifies Chrome DevTools Protocol (CDP) usage in Electron applications. This library provides an intuitive API for interacting with browser contexts, executing functions, and managing complex data serialization.

Readme

electron-cdp-utils

A powerful TypeScript library that simplifies Chrome DevTools Protocol (CDP) usage in Electron applications. This library provides an intuitive API for interacting with browser contexts, executing functions, and managing complex data serialization.

Features

  • 🚀 Easy CDP Integration: Simple API for Chrome DevTools Protocol commands
  • 🔧 Function Execution: Execute TypeScript/JavaScript functions in browser contexts with full type safety
  • 📦 SuperJSON Support: Advanced serialization for complex data types (Date, Map, Set, Error, Buffer, etc.)
  • 🎯 Type Safety: Full TypeScript support with comprehensive type definitions and strict typing
  • 🔄 Frame Management: Support for iframes and multiple execution contexts with automatic frame detection
  • Event Handling: Built-in event system for CDP events with proper type definitions
  • 🛠️ Function Exposure: Expose Node.js functions to browser contexts with retry and timeout options
  • 🔍 Execution Context Tracking: Monitor and manage browser execution contexts in real-time
  • 🔗 Auto Target Attachment: Automatically attach to related targets (iframes, workers, etc.)
  • 📱 Cross-Platform: Works on Windows, macOS, and Linux
  • 🎨 Modern API: Clean, intuitive API design with async/await support
  • 🔒 Session Management: Advanced session lifecycle management with proper cleanup
  • 🎭 Type-Safe Events: Strongly typed event system for better developer experience

Installation

npm install electron-cdp-utils

Quick Start

Basic Usage

import { attach } from 'electron-cdp-utils';
import { BrowserWindow } from 'electron';

const window = new BrowserWindow({
  webPreferences: {
    nodeIntegration: false,
    contextIsolation: true
  }
});

// Attach CDP functionality and get MainSession instance
const session = attach(window.webContents, '1.3');

// Setup the session with advanced options
await session.setup({
  preloadSuperJSON: true,
  trackExecutionContexts: true,
  autoAttachToRelatedTargets: ['page', 'iframe', 'worker']
});

// Use CDP commands
await session.send('Page.enable');
await session.send('Page.setBypassCSP', { enabled: true });
await session.send('Runtime.enable');

Using the Convenient WebContents Extension

import { attach } from 'electron-cdp-utils';

const window = new BrowserWindow({...});

// Attach and setup in one go
const session = attach(window.webContents, '1.3');
await session.setup({
  preloadSuperJSON: true,
  trackExecutionContexts: true
});

// Now you can use the convenient cdp property
await window.webContents.cdp.send('Page.enable');
await window.webContents.cdp.send('Page.setBypassCSP', { enabled: true });

MainSession Class

The MainSession class extends the base Session class with additional setup capabilities:

import { MainSession } from 'electron-cdp-utils';

// Create MainSession directly
const session = new MainSession(window.webContents, undefined, '1.3');

// Setup with options
await session.setup({
  preloadSuperJSON: (superJSON) => {
    // Customize SuperJSON instance
    superJSON.registerCustom({
      isApplicable: (v) => v instanceof MyCustomClass,
      serialize: (v) => v.toJSON(),
      deserialize: (v) => MyCustomClass.fromJSON(v)
    });
  },
  trackExecutionContexts: true,
  autoAttachToRelatedTargets: true
});

Core Concepts

Session Management

The library provides two main session classes:

Base Session Class

import { Session } from 'electron-cdp-utils';

// Create a base session directly
const session = new Session(window.webContents, sessionId, protocolVersion);

// Use for specific targets (iframes, workers, etc.)
const iframeSession = await Session.fromTargetId(webContents, targetId);

MainSession Class

import { MainSession, attach } from 'electron-cdp-utils';

// Create MainSession directly
const session = new MainSession(window.webContents, undefined, '1.3');
await session.setup({
  preloadSuperJSON: true,
  trackExecutionContexts: true
});

// Or use the convenient attach function
const session = attach(window.webContents, '1.3');
await session.setup({
  preloadSuperJSON: true,
  trackExecutionContexts: true
});

Key Differences

  • Session: Base class for all CDP communication, used for specific targets
  • MainSession: Extended class with setup capabilities, used for main WebContents
  • attach(): Convenient factory function that returns a MainSession instance

Function Execution

Execute functions in browser contexts with full type safety:

// Simple function execution
const result = await session.evaluate(() => {
  return document.title;
});

// With parameters
const result = await session.evaluate((message: string) => {
  console.log(message);
  return document.title;
}, 'Hello from browser!');

// With complex data types (thanks to SuperJSON)
const data = await session.evaluate((userData: { name: string; createdAt: Date }) => {
  return {
    ...userData,
    processedAt: new Date()
  };
}, { name: 'John', createdAt: new Date() });

Execution Contexts

Work with specific execution contexts:

// Get all execution contexts
const contexts = session.executionContexts;

// Execute in a specific context
const context = contexts.get(contextId);
const result = await context.evaluate(() => {
  return window.location.href;
});

Event Handling

Listen to CDP events with full type safety:

// Listen to console messages
session.on('Runtime.consoleAPICalled', (params) => {
  console.log('Console message:', params);
});

// Listen to page load events
session.on('Page.loadEventFired', () => {
  console.log('Page loaded!');
});

// Listen to execution context events
session.on('execution-context-created', (context) => {
  console.log('New execution context:', context.id);
});

// Listen to session lifecycle events
session.on('session-attached', (newSession, url) => {
  console.log('New session attached:', newSession.id, url);
});

session.on('session-detached', (detachedSession, reason) => {
  console.log('Session detached:', detachedSession.id, reason);
});

Function Exposure

Expose Node.js functions to browser contexts:

// Expose a simple function
await session.exposeFunction('getSystemInfo', () => {
  return {
    platform: process.platform,
    version: process.version
  };
});

// Expose with options
await session.exposeFunction('complexOperation', async (data: any) => {
  // Complex operation here
  return processedData;
}, {
  mode: 'CDP',
  withReturnValue: true,
  retry: { count: 3, delay: 1000 }
});

Advanced Features

MainSession Setup Options

The MainSession.setup() method provides comprehensive configuration:

const session = attach(window.webContents, '1.3');
await session.setup({
  // SuperJSON configuration
  preloadSuperJSON: true, // or a custom function
  preloadSuperJSON: (superJSON) => {
    // Customize SuperJSON instance
    superJSON.registerCustom({
      isApplicable: (v) => v instanceof MyClass,
      serialize: (v) => v.toJSON(),
      deserialize: (v) => MyClass.fromJSON(v)
    });
  },
  
  // Execution context tracking
  trackExecutionContexts: true,
  
  // Auto target attachment
  autoAttachToRelatedTargets: true, // all targets
  autoAttachToRelatedTargets: ['iframe', 'worker', 'service_worker'], // specific types
});

Service Worker Support

Enhanced service worker support with automatic event handling:

const session = attach(window.webContents, '1.3');
await session.setup({
  autoAttachToRelatedTargets: ['service_worker']
});

// Listen for service worker events
session.on('service-worker-running-status-changed', (event, session) => {
  console.log('Service worker status:', event.runningStatus);
  console.log('Version ID:', event.versionId);
});

session.on('service-worker-version-updated', (version, session) => {
  console.log('Service worker updated:', version.versionId);
  console.log('Scope URL:', version.scopeURL);
});

// Expose functions to service workers
await session.exposeFunction('serviceWorkerFunction', (data) => {
  console.log('Called from service worker:', data);
  return { processed: true, timestamp: new Date() };
});

SuperJSON Integration

The library includes SuperJSON for advanced serialization:

// Complex data types are automatically handled
const result = await session.evaluate((data) => {
  // data is properly deserialized
  return {
    original: data,
    processed: new Map([['key', 'value']]),
    timestamp: new Date()
  };
}, {
  map: new Map([['key', 'value']]),
  set: new Set([1, 2, 3]),
  date: new Date(),
  buffer: Buffer.from('hello')
});

Frame Management

Work with iframes and multiple frames:

// The library automatically handles frame creation and navigation
window.webContents.on('frame-created', (event, details) => {
  console.log('New frame created:', details.frameId);
});

// Execute in specific frames
const frame = webFrameMain.fromId(processId, routingId);
const result = await frame.evaluate(() => {
  return document.title;
});

Error Handling

Comprehensive error handling with detailed information:

try {
  const result = await session.evaluate(() => {
    throw new Error('Something went wrong');
  });
} catch (error) {
  console.error('Execution error:', error);
  // Error includes stack trace, line numbers, and context
}

API Reference

For detailed API documentation, see API.md.

Quick Reference

MainSession Class

  • setup() - Configure session with options
  • send() - Send CDP commands
  • evaluate() - Execute functions in browser context
  • exposeFunction() - Expose Node.js functions to browser
  • setAutoAttach() - Enable auto target attachment
  • enableTrackExecutionContexts() - Enable execution context tracking

Session Class (Base)

  • send() - Send CDP commands
  • evaluate() - Execute functions in browser context
  • exposeFunction() - Expose Node.js functions to browser
  • fromTargetId() - Create session from target ID
  • fromTargetInfo() - Create session from target info
  • fromSessionId() - Create session from session ID

Key Types

  • SessionWithId - Session with guaranteed ID
  • DetachedSession - Detached session with limited functionality
  • DetachedSessionWithId - Detached session with guaranteed ID
  • ServiceWorkerVersion - Enhanced service worker version with scope URL
  • Target - Target information with initial URL

TypeScript Support

The library provides comprehensive TypeScript definitions:

import { Protocol } from 'electron-cdp-utils';

// Use CDP protocol types
const result: Protocol.Runtime.EvaluateResponse = await session.send('Runtime.evaluate', {
  expression: '1 + 1'
});

Auto Target Attachment

The library can automatically attach to related targets like iframes and workers:

// Create and setup session with auto attachment
const session = attach(window.webContents, '1.3');
await session.setup({
  autoAttachToRelatedTargets: true
});

// Or specify target types
const session = attach(window.webContents, '1.3');
await session.setup({
  autoAttachToRelatedTargets: ['iframe', 'worker', 'shared_worker', 'service_worker']
});

// Listen for new sessions
session.on('session-attached', (newSession, url) => {
  console.log('New target attached:', newSession.target.type, url);
});

// Listen for service worker events
session.on('service-worker-running-status-changed', (event, session) => {
  console.log('Service worker status changed:', event.runningStatus);
});

Execution Context Tracking

Monitor execution contexts in real-time:

const session = attach(window.webContents, '1.3');
await session.setup({
  trackExecutionContexts: true
});

// Access all execution contexts
console.log('Available contexts:', session.executionContexts.size);

// Listen for context events
session.on('execution-context-created', (context) => {
  console.log('New context created:', context.id);
});

session.on('execution-context-destroyed', (contextId) => {
  console.log('Context destroyed:', contextId);
});

session.on('execution-contexts-cleared', () => {
  console.log('All execution contexts cleared');
});

Common Use Cases

Web Scraping

const session = attach(window.webContents, '1.3');
await session.setup({
  preloadSuperJSON: true,
  trackExecutionContexts: true
});

// Navigate to page
await session.send('Page.navigate', { url: 'https://example.com' });
await session.send('Page.loadEventFired');

// Extract data with complex types
const data = await session.evaluate(() => {
  return {
    title: document.title,
    links: Array.from(document.querySelectorAll('a')).map(a => ({
      href: a.href,
      text: a.textContent,
      timestamp: new Date()
    })),
    images: Array.from(document.querySelectorAll('img')).map(img => ({
      src: img.src,
      alt: img.alt,
      dimensions: { width: img.width, height: img.height }
    }))
  };
});

Testing and Automation

const session = attach(window.webContents, '1.3');
await session.setup({
  preloadSuperJSON: true,
  autoAttachToRelatedTargets: true
});

// Fill form with complex data
const formData = {
  username: 'test',
  password: 'secret',
  preferences: new Map([['theme', 'dark'], ['notifications', true]]),
  lastLogin: new Date()
};

await session.evaluate((data) => {
  document.querySelector('#username').value = data.username;
  document.querySelector('#password').value = data.password;
  document.querySelector('#preferences').value = JSON.stringify(data.preferences);
  document.querySelector('#login-form').submit();
}, formData);

// Wait for navigation and handle iframes
session.on('session-attached', (newSession) => {
  if (newSession.target.type === 'iframe') {
    console.log('Iframe detected:', newSession.target.initialURL);
  }
});

Performance Monitoring

const session = attach(window.webContents, '1.3');
await session.setup({
  trackExecutionContexts: true,
  autoAttachToRelatedTargets: ['worker', 'service_worker']
});

// Enable performance monitoring
await session.send('Performance.enable');
await session.send('Runtime.enable');

// Listen for performance metrics
session.on('Performance.metrics', (params) => {
  console.log('Performance metrics:', params.metrics);
});

// Monitor service worker performance
session.on('service-worker-running-status-changed', (event, session) => {
  console.log('Service worker status:', event.runningStatus);
});

// Get memory usage with complex data
const memory = await session.evaluate(() => {
  const memInfo = performance.memory;
  return {
    used: memInfo.usedJSHeapSize,
    total: memInfo.totalJSHeapSize,
    limit: memInfo.jsHeapSizeLimit,
    timestamp: new Date(),
    contexts: Array.from(document.querySelectorAll('iframe')).length
  };
});

Troubleshooting

Common Issues

1. CDP Connection Failed

// Ensure debugger is attached
if (!webContents.debugger.isAttached()) {
  webContents.debugger.attach('1.3');
}

2. Function Execution Timeout

// Increase timeout for long-running functions
const result = await session.evaluate(() => {
  // Long-running operation
}, { timeout: 30000 }); // 30 seconds

3. Serialization Issues

// Use SuperJSON for complex data types
await session.enableSuperJSON();
const result = await session.evaluate((data) => {
  return new Map(Object.entries(data));
}, { key: 'value' });

Requirements

  • Node.js 14+
  • Electron 13+
  • TypeScript 4.5+ (for TypeScript projects)

License

ISC

Documentation

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Best Practices

Session Management

// Always check if session is attached before using
if (session.id) {
  // Session is attached to a specific target
  console.log('Session ID:', session.id);
}

// Use proper cleanup
process.on('beforeExit', async () => {
  await session.detach();
});

Error Handling

try {
  const result = await session.evaluate(() => {
    // Your code here
  });
} catch (error) {
  if (error.message.includes('target closed')) {
    console.log('Target was closed, session may be detached');
  } else {
    console.error('Execution error:', error);
  }
}

Performance Optimization

// Enable SuperJSON preloading for better performance
const session = attach(window.webContents, '1.3');
await session.setup({
  preloadSuperJSON: true
});

// Use execution context tracking only when needed
const session = attach(window.webContents, '1.3');
await session.setup({
  trackExecutionContexts: true
});

// Customize SuperJSON for better serialization
const session = attach(window.webContents, '1.3');
await session.setup({
  preloadSuperJSON: (superJSON) => {
    // Register custom transformers for your data types
    superJSON.registerCustom({
      isApplicable: (v) => v instanceof MyCustomClass,
      serialize: (v) => v.toJSON(),
      deserialize: (v) => MyCustomClass.fromJSON(v)
    });
  }
});

Changelog

See CHANGELOG.md for a detailed list of changes and version history.