How the installEgoSdk Function Wraps Helpers with Ready Signal Handling

The installEgoSdk function in citrolabs/ego-lite normalizes an optional ready promise and wraps every asynchronous helper via wrapReady so that all helper calls automatically wait for the browser runtime to initialize before executing.

The installEgoSdk function serves as the main entry point for injecting Ego-Browser helpers into a target object such as globalThis. When you call this function with an optional ready signal, it guarantees that every subsequent helper invocation respects the underlying browser runtime's initialization state. This design is implemented in the ego-browser package within the citrolabs/ego-lite repository, as shown in package/ego-browser/src/index.ts.

Ready Signal Normalization and Error Capture

Before any helper is exposed, installEgoSdk prepares the ready signal in src/index.ts. It converts the user-provided options.ready value into a standard promise:

const readySignal = Promise.resolve(options.ready);

(See line 57 of src/index.ts.)

Immediately after creation, a .catch handler attaches to capture any early rejection. If the ready promise fails during initialization, the first error is stored in readyError (lines 58-61). This allows the SDK to propagate the exact same failure to every future helper call instead of swallowing it.

Classifying Sync and Async Helpers

Once the ready signal is secured, installEgoSdk iterates over every helper provided by helperContext() in src/helpers.ts. For each name/value pair, it checks whether the helper belongs to the SYNC_HELPERS set:

  • Sync helpers are exposed directly without modification.
  • Async helpers are passed through wrapReady, which returns a wrapped function or object that pauses execution until readySignal resolves (lines 63-67).

This classification ensures that lightweight synchronous utilities remain unaffected while all asynchronous browser operations respect the ready state.

Inside the wrapReady Implementation

The core wrapping logic lives in wrapReady (lines 19-47 of src/index.ts). It inspects the helper type and applies the appropriate wrapper.

Wrapping Functions

If the helper is a function, wrapReady returns a new async function that performs three steps:

  1. Awaits readySignal.
  2. Checks readyError and re-throws if an initialization failure occurred.
  3. Calls the original helper with the provided arguments.

This means a call like page.goto(...) automatically stalls until the browser session and CDP transport are fully available.

Wrapping Objects Recursively

When the helper is an object, wrapReady recursively wraps every property. This ensures that nested helper namespaces also wait for the ready signal before executing any method.

Factory Helper Special Case

A special check for isSyncFactoryHelper allows factory helpers that return synchronous objects to be wrapped correctly. Without this branch, factory functions could return unwrapped objects that bypass the ready check.

Exposing Helpers on the Target

After wrapping, installEgoSdk defines each helper on the target object using Object.defineProperty (lines 67-72). This creates a clean property for every helper so that user scripts can call them as if they were native globals, while the underlying promise logic remains transparent. You can also see how the module is loaded as a library in package/ego-browser/src/run.ts.

Practical Usage Example

Here is how you install the SDK with a custom ready promise and invoke a wrapped helper:

// Example: install the SDK with a ready promise that resolves when the browser is ready
import { installEgoSdk } from "ego-browser";

const ready = new Promise<void>((resolve) => {
  // Imagine the host sets up the browser and calls resolve() when done
  setTimeout(resolve, 2_000); // simulate async init
});

installEgoSdk(globalThis, { ready });

// Later in the script – this call will wait for the ready promise first
await page.goto("https://example.com");   // `page.goto` is wrapped by installEgoSdk

Under the hood, the wrapper generated by wrapReady looks conceptually like this:

function wrapReady(value, readySignal, readyError) {
  if (typeof value === "function") {
    return async (...args) => {
      await readySignal;                     // wait for the SDK to be ready
      const err = readyError();
      if (err) throw err;                     // propagate early init errors
      return value(...args);                  // finally call the original helper
    };
  }
  // Objects are recursively wrapped so nested helpers also wait
  // …
}

Summary

  • installEgoSdk accepts an optional ready promise in options.ready and normalizes it via Promise.resolve in src/index.ts.
  • A .catch handler captures the first initialization error in readyError so all later calls fail consistently.
  • Helpers from helperContext() are split into synchronous and asynchronous groups; only async helpers are wrapped.
  • wrapReady (lines 19-47) generates async wrappers for functions and recursively wraps objects, with special handling for factory helpers.
  • Wrapped helpers are attached to the target via Object.defineProperty (lines 67-72), making the ready check transparent to consumers.

Frequently Asked Questions

What is the purpose of the ready signal in installEgoSdk?

The ready signal lets the host application tell the SDK when the underlying browser runtime and CDP transport are fully initialized. It prevents helpers from executing before the environment is ready, which avoids race conditions and undefined behavior.

How does installEgoSdk handle helpers that are synchronous?

Helpers listed in the SYNC_HELPERS set are exposed directly on the target without being passed through wrapReady. They do not wait for the ready promise because they do not interact with the asynchronous browser runtime.

What happens if the ready promise rejects?

If options.ready rejects, the error is captured in readyError inside src/index.ts. Every subsequent call to a wrapped async helper will await the rejected promise, check readyError, and re-throw the same error, ensuring consistent failure handling across the SDK.

Where are the helper definitions sourced from in ego-lite?

The helpers are supplied by helperContext(), which is defined in package/ego-browser/src/helpers.ts. installEgoSdk imports this context and iterates over its entries to decide which ones to wrap and expose.

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 →