How ensureSession() Works in ego-lite: CDP Session Management Explained

The ensureSession() function in citrolabs/ego-lite guarantees a valid Chrome DevTools Protocol (CDP) session by validating cached sessions against a TTL, deduplicating concurrent attach requests, discovering active browser tabs, and initializing page event listeners before returning a session identifier.

The ensureSession() function serves as the foundational gatekeeper for all browser-level operations in ego-lite, an open-source browser automation framework. Before any CDP command executes, this helper validates connection state to ensure seamless interaction with the embedded Chrome instance. According to the source code in package/ego-browser/src/browser-runtime.ts, the function implements an eight-stage lifecycle that balances performance caching with connection reliability.

The Eight-Stage Session Lifecycle

The implementation spans lines 107-140 of browser-runtime.ts, executing atomically through the following phases:

  1. Cache Validation – If state.sessionId exists and Date.now() - state.sessionAt < SESSION_TTL_MS, the function returns the cached identifier immediately, avoiding unnecessary re-attachment overhead.

  2. In-Flight Deduplication – When multiple callers request sessions simultaneously, the first caller creates a promise stored in state.sessionInflight. Subsequent callers return this same promise, ensuring only one attach sequence runs concurrently.

  3. Tab Discovery – The function invokes browserEgo().listTabs() to retrieve current target information. It prioritizes state.preferredTargetId if set, otherwise selects the first active tab, falling back to the last available tab.

  4. Tab Validation – If no active tab is discovered, the function throws an explicit error: "no active tab to attach session", preventing silent failures downstream.

  5. Session Attachment – When the discovered targetId differs from state.sessionTargetId or no session exists, the function calls Target.attachToTarget to establish a new CDP session, storing the returned sessionId.

  6. Event Initialization – Immediately after attachment, enablePageEvents(state.sessionId) registers listeners for page-level CDP events including DOM updates and console messages.

  7. Timestamp Refresh – The function updates state.sessionAt = Date.now() to reset the TTL clock for subsequent cache checks.

  8. Cleanup – Regardless of success or failure, the finally block clears state.sessionInflight = null, allowing future calls to initiate new attach sequences.

Source Code Architecture

In package/ego-browser/src/browser-runtime.ts, the ensureSession() function interacts with mutable state managed in package/ego-browser/src/state.ts. The state object tracks sessionId, sessionAt, sessionInflight, preferredTargetId, and sessionTargetId across the application lifecycle.

The function distinguishes between browser-level operations and page-level commands through the BROWSER_LEVEL(method) check. Unless operating at browser scope, higher-level helpers like cdp() and js() automatically invoke ensureSession() before transmitting commands, making session management transparent to end users.

Practical Usage Examples

Direct session retrieval leverages the caching mechanism for optimal performance:

import { ensureSession } from 'ego-browser';

// Obtain a cached session ID valid for SESSION_TTL_MS
const sessionId = await ensureSession();
console.log('Active CDP session:', sessionId);

Higher-level helpers implicitly manage sessions during CDP execution:

import { cdp } from 'ego-browser';

// Runtime.evaluate automatically triggers ensureSession()
const result = await cdp('Runtime.evaluate', { 
  expression: 'document.title' 
});
console.log('Page title:', result.result.value);

Concurrent calls demonstrate the deduplication logic:

// Both calls share the same attach promise
const [s1, s2] = await Promise.all([
  ensureSession(), 
  ensureSession()
]);
console.log(s1 === s2); // true - single attachment performed

Force re-attachment after navigation invalidates the current tab:

import { invalidateSession, ensureSession } from 'ego-browser';

await invalidateSession(); // Clears cached state
const freshId = await ensureSession(); // Re-attaches to current active tab

Supporting Files and Dependencies

The session management ecosystem spans multiple modules:

  • package/ego-browser/src/state.ts – Maintains runtime mutable state including session timestamps and inflight promises.
  • package/ego-browser/src/cdp-eval.ts – Exports cdp() and js() wrappers that depend on ensureSession() for non-browser-level operations.
  • package/ego-browser/src/driver/ – Navigation, screencast, and download drivers invoke ensureSession() before issuing protocol commands.
  • package/ego-browser/src/browser-runtime.test.mjs – Validates caching behavior, TTL expiration, concurrent deduplication, and tab selection logic.

Summary

  • ensureSession() validates cached CDP sessions against SESSION_TTL_MS before initiating expensive attach operations.
  • Concurrent deduplication prevents redundant attachment attempts when multiple async callers request sessions simultaneously.
  • Tab selection logic prioritizes preferred targets, then active tabs, falling back to the last available tab to ensure connection stability.
  • Automatic lifecycle management enables event listeners and state cleanup without manual intervention, supporting transparent operation through higher-level APIs like cdp() and js().

Frequently Asked Questions

What triggers ensureSession() to attach a new session instead of using the cache?

The function attaches a new session when the cached session ID is missing, the TTL has expired (Date.now() - state.sessionAt >= SESSION_TTL_MS), or when the current target ID differs from state.sessionTargetId. This ensures the CDP session always matches the active browser tab after navigation or context switches.

How does ensureSession() handle multiple simultaneous calls?

When ensureSession() receives concurrent requests while no valid session exists, the first call creates a promise stored in state.sessionInflight. Subsequent calls detect this promise and return it immediately, ensuring only one Target.attachToTarget operation executes despite multiple callers.

What happens if no browser tabs are available when ensureSession() runs?

If browserEgo().listTabs() returns an empty list or no active tab is found, the function throws new Error("no active tab to attach session") at lines 123-125 of browser-runtime.ts. This explicit failure prevents undefined behavior in downstream CDP operations.

Can I force ensureSession() to bypass the cache and create a fresh session?

While ensureSession() itself does not accept parameters to bypass caching, you can invalidate the current session by calling invalidateSession(), which clears state.sessionId and state.sessionTargetId. The next call to ensureSession() will then execute a fresh attach sequence to the current active tab.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →