or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-web-features.mdbrowser-page-control.mdcore-debugging.mddevice-testing.mddom-styling.mdindex.mdnetwork-performance.mdstorage-data.md
tile.json

browser-page-control.mddocs/

Browser and Page Control

Browser-level operations, page navigation, lifecycle management, and target control. This covers domains that manage browser windows, page navigation, and debugging target management.

Capabilities

Browser Domain

Browser-level operations and window management for controlling browser instances and sessions.

namespace Protocol.Browser {
  type BrowserContextID = string;
  type WindowID = integer;
  type WindowState = ('normal' | 'minimized' | 'maximized' | 'fullscreen');

  interface GetVersionResponse {
    protocolVersion: string;
    product: string;
    revision: string;
    userAgent: string;
    jsVersion: string;
  }

  interface GetBrowserContextsResponse {
    browserContextIds: BrowserContextID[];
  }

  interface CreateBrowserContextRequest {
    disposeOnDetach?: boolean;
    proxyServer?: string;
    proxyBypassList?: string;
    originsWithUniversalNetworkAccess?: string[];
  }

  interface CreateBrowserContextResponse {
    browserContextId: BrowserContextID;
  }

  interface GetWindowBoundsRequest {
    windowId: WindowID;
  }

  interface GetWindowBoundsResponse {
    bounds: Bounds;
  }

  interface SetWindowBoundsRequest {
    windowId: WindowID;
    bounds: Bounds;
  }

  interface Bounds {
    left?: integer;
    top?: integer;
    width?: integer;
    height?: integer;
    windowState?: WindowState;
  }

  interface GetWindowForTargetRequest {
    targetId?: Target.TargetID;
  }

  interface GetWindowForTargetResponse {
    windowId: WindowID;
    bounds: Bounds;
  }
}

Usage Example:

import Protocol from "devtools-protocol/types/protocol";

// Get browser version information
function getBrowserInfo(): Promise<Protocol.Browser.GetVersionResponse> {
  // Implementation would send Browser.getVersion command
  return Promise.resolve({
    protocolVersion: "1.3",
    product: "Chrome/91.0.4472.124",
    revision: "@abc123",
    userAgent: "Mozilla/5.0...",
    jsVersion: "9.1.269.38"
  });
}

// Create isolated browser context
const createContextRequest: Protocol.Browser.CreateBrowserContextRequest = {
  disposeOnDetach: true,
  proxyServer: "http://proxy.example.com:8080"
};

// Manage window bounds
const windowBounds: Protocol.Browser.Bounds = {
  left: 100,
  top: 100,
  width: 1200,
  height: 800,
  windowState: 'normal'
};

Page Domain

Page-level operations including navigation, lifecycle management, and resource handling.

namespace Protocol.Page {
  type FrameId = string;
  type LoaderId = string;
  type NavigationId = string;
  type TransitionType = ('link' | 'typed' | 'address_bar' | 'auto_bookmark' | 'auto_subframe' | 'manual_subframe' | 'generated' | 'auto_toplevel' | 'form_submit' | 'reload' | 'keyword' | 'keyword_generated' | 'other');
  type ReferrerPolicy = ('noReferrer' | 'noReferrerWhenDowngrade' | 'origin' | 'originWhenCrossOrigin' | 'sameOrigin' | 'strictOrigin' | 'strictOriginWhenCrossOrigin' | 'unsafeUrl');

  interface Frame {
    id: FrameId;
    parentId?: string;
    loaderId: LoaderId;
    name?: string;
    url: string;
    urlFragment?: string;
    domainAndRegistry: string;
    securityOrigin: string;
    mimeType: string;
    unreachableUrl?: string;
    adFrameStatus?: AdFrameStatus;
    secureContextType: SecureContextType;
    crossOriginIsolatedContextType: CrossOriginIsolatedContextType;
    gatedAPIFeatures: GatedAPIFeatures[];
  }

  interface NavigateRequest {
    url: string;
    referrer?: string;
    transitionType?: TransitionType;
    frameId?: FrameId;
    referrerPolicy?: ReferrerPolicy;
  }

  interface NavigateResponse {
    frameId: FrameId;
    loaderId?: LoaderId;
    errorText?: string;
  }

  interface ReloadRequest {
    ignoreCache?: boolean;
    scriptToEvaluateOnLoad?: string;
    loaderId?: LoaderId;
  }

  interface GetResourceTreeResponse {
    frameTree: FrameResourceTree;
  }

  interface FrameResourceTree {
    frame: Frame;
    childFrames?: FrameResourceTree[];
    resources: FrameResource[];
  }

  interface FrameResource {
    url: string;
    type: Network.ResourceType;
    mimeType: string;
    lastModified?: Network.TimeSinceEpoch;
    contentSize?: integer;
    failed?: boolean;
    canceled?: boolean;
  }

  interface DomContentEventFiredEvent {
    timestamp: Network.MonotonicTime;
  }

  interface LoadEventFiredEvent {
    timestamp: Network.MonotonicTime;
  }

  interface FrameNavigatedEvent {
    frame: Frame;
    type: NavigationType;
  }

  interface FrameStartedLoadingEvent {
    frameId: FrameId;
  }

  interface FrameStoppedLoadingEvent {
    frameId: FrameId;
  }

  interface LifecycleEvent {
    frameId: FrameId;
    loaderId: LoaderId;
    name: string;
    timestamp: Network.MonotonicTime;
  }
}

Usage Example:

import Protocol from "devtools-protocol/types/protocol";

// Navigate to a URL
const navigateRequest: Protocol.Page.NavigateRequest = {
  url: "https://example.com",
  referrerPolicy: 'origin',
  transitionType: 'typed'
};

// Handle page lifecycle events
function onDomContentLoaded(event: Protocol.Page.DomContentEventFiredEvent) {
  console.log("DOM content loaded at:", event.timestamp);
}

function onPageLoaded(event: Protocol.Page.LoadEventFiredEvent) {
  console.log("Page fully loaded at:", event.timestamp);
}

function onFrameNavigated(event: Protocol.Page.FrameNavigatedEvent) {
  console.log(`Frame navigated to: ${event.frame.url}`);
}

// Get page resource tree
function analyzePageResources(resourceTree: Protocol.Page.FrameResourceTree) {
  console.log(`Main frame: ${resourceTree.frame.url}`);
  console.log(`Resources: ${resourceTree.resources.length}`);
  
  resourceTree.resources.forEach(resource => {
    console.log(`- ${resource.url} (${resource.type}, ${resource.mimeType})`);
  });
  
  if (resourceTree.childFrames) {
    resourceTree.childFrames.forEach(childFrame => {
      analyzePageResources(childFrame);
    });
  }
}

Target Domain

Debug target management and discovery for controlling multiple debugging contexts.

namespace Protocol.Target {
  type TargetID = string;
  type SessionID = string;
  type BrowserContextID = string;

  interface TargetInfo {
    targetId: TargetID;
    type: string;
    title: string;
    url: string;
    attached: boolean;
    openerId?: TargetID;
    canAccessOpener: boolean;
    openerFrameId?: Page.FrameId;
    browserContextId?: BrowserContextID;
    subtype?: string;
  }

  interface CreateTargetRequest {
    url: string;
    width?: integer;
    height?: integer;
    browserContextId?: BrowserContextID;
    enableBeginFrameControl?: boolean;
    newWindow?: boolean;
    background?: boolean;
    forTab?: boolean;
  }

  interface CreateTargetResponse {
    targetId: TargetID;
  }

  interface AttachToTargetRequest {
    targetId: TargetID;
    flatten?: boolean;
  }

  interface AttachToTargetResponse {
    sessionId: SessionID;
  }

  interface DetachFromTargetRequest {
    sessionId?: SessionID;
    targetId?: TargetID;
  }

  interface GetTargetsResponse {
    targetInfos: TargetInfo[];
  }

  interface CreateBrowserContextRequest {
    disposeOnDetach?: boolean;
    proxyServer?: string;
    proxyBypassList?: string;
    originsWithUniversalNetworkAccess?: string[];
  }

  interface CreateBrowserContextResponse {
    browserContextId: BrowserContextID;
  }

  interface TargetCreatedEvent {
    targetInfo: TargetInfo;
  }

  interface TargetDestroyedEvent {
    targetId: TargetID;
  }

  interface TargetCrashedEvent {
    targetId: TargetID;
    status: string;
    errorCode: integer;
  }

  interface TargetInfoChangedEvent {
    targetInfo: TargetInfo;
  }

  interface AttachedToTargetEvent {
    sessionId: SessionID;
    targetInfo: TargetInfo;
    waitingForDebugger: boolean;
  }

  interface DetachedFromTargetEvent {
    sessionId: SessionID;
    targetId?: TargetID;
  }
}

Usage Example:

import Protocol from "devtools-protocol/types/protocol";

// Create a new target (tab/window)
const createTargetRequest: Protocol.Target.CreateTargetRequest = {
  url: "about:blank",
  width: 1024,
  height: 768,
  newWindow: false,
  background: false
};

// Attach to a target for debugging
async function attachToTarget(targetId: string): Promise<string> {
  const attachRequest: Protocol.Target.AttachToTargetRequest = {
    targetId,
    flatten: true
  };
  
  // Would return session ID for further communication
  return "session_id_123";
}

// Handle target lifecycle events
function onTargetCreated(event: Protocol.Target.TargetCreatedEvent) {
  const { targetInfo } = event;
  console.log(`New target created: ${targetInfo.title} (${targetInfo.url})`);
}

function onTargetDestroyed(event: Protocol.Target.TargetDestroyedEvent) {
  console.log(`Target destroyed: ${event.targetId}`);
}

function onTargetCrashed(event: Protocol.Target.TargetCrashedEvent) {
  console.error(`Target crashed: ${event.targetId}, status: ${event.status}`);
}

// Manage multiple targets
async function listAllTargets(): Promise<Protocol.Target.TargetInfo[]> {
  // Implementation would call Target.getTargets
  return [
    {
      targetId: "target_1",
      type: "page",
      title: "Example Page",
      url: "https://example.com",
      attached: true,
      canAccessOpener: false
    }
  ];
}

Inspector Domain

Inspector connection and session management for controlling debugging sessions.

namespace Protocol.Inspector {
  interface DetachedEvent {
    reason: string;
  }

  interface TargetCrashedEvent {}

  interface TargetReloadedAfterCrashEvent {}
}

Common Usage Patterns

Browser Session Management

import Protocol from "devtools-protocol/types/protocol";

class BrowserSessionManager {
  private contexts: Map<string, Protocol.Browser.BrowserContextID> = new Map();
  private targets: Map<string, Protocol.Target.TargetID> = new Map();

  async createIsolatedContext(name: string): Promise<Protocol.Browser.BrowserContextID> {
    const request: Protocol.Browser.CreateBrowserContextRequest = {
      disposeOnDetach: true
    };
    
    // Implementation would send Browser.createBrowserContext
    const response = { browserContextId: `context_${name}` };
    this.contexts.set(name, response.browserContextId);
    return response.browserContextId;
  }

  async createTabInContext(contextId: Protocol.Browser.BrowserContextID, url: string): Promise<Protocol.Target.TargetID> {
    const request: Protocol.Target.CreateTargetRequest = {
      url,
      browserContextId: contextId,
      newWindow: false,
      background: false
    };
    
    // Implementation would send Target.createTarget
    const response = { targetId: `target_${Date.now()}` };
    this.targets.set(url, response.targetId);
    return response.targetId;
  }

  async navigateTarget(targetId: Protocol.Target.TargetID, url: string): Promise<void> {
    const request: Protocol.Page.NavigateRequest = {
      url
    };
    
    // Implementation would send Page.navigate to the target
  }
}

Page Navigation and Lifecycle

import Protocol from "devtools-protocol/types/protocol";
import { ProtocolMapping } from "devtools-protocol/types/protocol-mapping";

class PageManager {
  private frameTree: Protocol.Page.FrameResourceTree | null = null;
  
  setupPageListeners() {
    // Handle navigation events
    this.onFrameNavigated = (event: ProtocolMapping.Events['Page.frameNavigated'][0]) => {
      console.log(`Navigation: ${event.frame.url}`);
      this.updateFrameTree();
    };
    
    // Handle lifecycle events
    this.onLifecycleEvent = (event: ProtocolMapping.Events['Page.lifecycleEvent'][0]) => {
      console.log(`Lifecycle: ${event.name} for frame ${event.frameId}`);
    };
    
    // Handle load events
    this.onLoadEventFired = (event: ProtocolMapping.Events['Page.loadEventFired'][0]) => {
      console.log(`Page loaded at: ${event.timestamp}`);
    };
  }

  async reloadPage(ignoreCache: boolean = false): Promise<void> {
    const request: Protocol.Page.ReloadRequest = {
      ignoreCache,
      scriptToEvaluateOnLoad: "console.log('Page reloaded');"
    };
    
    // Implementation would send Page.reload
  }

  private async updateFrameTree(): Promise<void> {
    // Implementation would call Page.getResourceTree
    this.frameTree = {
      frame: {
        id: "main_frame",
        loaderId: "loader_123",
        url: "https://example.com",
        domainAndRegistry: "example.com",
        securityOrigin: "https://example.com",
        mimeType: "text/html",
        secureContextType: "Secure",
        crossOriginIsolatedContextType: "NotIsolated",
        gatedAPIFeatures: []
      },
      resources: []
    };
  }
}

Multi-Target Debugging

import Protocol from "devtools-protocol/types/protocol";

class MultiTargetDebugger {
  private sessions: Map<Protocol.Target.SessionID, Protocol.Target.TargetInfo> = new Map();

  async attachToAllTargets(): Promise<void> {
    // Get all available targets
    const targets = await this.getAllTargets();
    
    for (const target of targets) {
      if (target.type === 'page' && !target.attached) {
        const sessionId = await this.attachToTarget(target.targetId);
        this.sessions.set(sessionId, target);
        
        // Enable debugging for this target
        await this.enableDebuggingForSession(sessionId);
      }
    }
  }

  private async getAllTargets(): Promise<Protocol.Target.TargetInfo[]> {
    // Implementation would call Target.getTargets
    return [];
  }

  private async attachToTarget(targetId: Protocol.Target.TargetID): Promise<Protocol.Target.SessionID> {
    const request: Protocol.Target.AttachToTargetRequest = {
      targetId,
      flatten: true
    };
    
    // Implementation would send Target.attachToTarget
    return `session_${Date.now()}`;
  }

  private async enableDebuggingForSession(sessionId: Protocol.Target.SessionID): Promise<void> {
    // Enable domains for this session
    // Implementation would send commands to the specific session
  }

  handleTargetEvents() {
    this.onTargetCreated = (event: Protocol.Target.TargetCreatedEvent) => {
      console.log(`New target: ${event.targetInfo.title}`);
      // Automatically attach to new targets if needed
    };

    this.onTargetDestroyed = (event: Protocol.Target.TargetDestroyedEvent) => {
      console.log(`Target destroyed: ${event.targetId}`);
      // Clean up session if it exists
      for (const [sessionId, targetInfo] of this.sessions.entries()) {
        if (targetInfo.targetId === event.targetId) {
          this.sessions.delete(sessionId);
          break;
        }
      }
    };
  }
}