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 🙏

© 2026 – Pkg Stats / Ryan Hefner

electrobun-browser-tools

v1.0.1

Published

Incur-based inspection CLI for Electrobun app/window/view/layout state.

Readme

electrobun-browser-tools

Inspection-first bridge, CLI, and Playwright-style driver for Electrobun and Electron-backed desktop apps.

It models the runtime as:

app -> window -> view -> layout -> node

The package now has two complementary surfaces:

  • electrobun-browser-tools: programmatic JS client, inspection CLI, bridge mounting helpers, catalog metadata, and shared types
  • electrobun-browser-tools/bridge: runtime-side bridge mounting helpers

Mount The Bridge

The CLI and driver only work against apps that expose the bridge.

For Electrobun apps, the standard setup is:

import { mountElectrobunToolBridge } from 'electrobun-browser-tools/bridge'

await mountElectrobunToolBridge({
  mainWindow,
})

That starts a local Bun endpoint, registers the app by appId, and exposes the inspection and driver commands over the same transport.

Common optional inputs include:

  • appId, appName, appVersion
  • state
  • instrumentation
  • describeView, describeWindow
  • getActiveViewId, getActiveWindowId
  • windows, browserView, buildConfig

Use mountToolBridge(...) when you want the built-in server with a custom adapter. Use createToolBridge(...) when you want the fetch handler and will mount it yourself.

Inspection Mode

Inspection mode is still the baseline capability set. It is read-heavy and centered on discovery, layout snapshots, live DOM reads, buffered events/logs/errors, state namespaces, and optional capture/network/perf helpers.

Start with machine-readable output:

electrobun-browser-tools catalog --json
electrobun-browser-tools doctor --app <app-id> --json
electrobun-browser-tools status --app <app-id> --json
electrobun-browser-tools tree --app <app-id> --json
electrobun-browser-tools layout snapshot --app <app-id> --summary --json

Then drill into one target:

electrobun-browser-tools layout explain testid:checkout-submit --app <app-id> --json
electrobun-browser-tools dom html testid:checkout-submit --outer --app <app-id> --json
electrobun-browser-tools events tail --types dialog.opened --app <app-id> --json
electrobun-browser-tools logs summary --app <app-id> --json
electrobun-browser-tools state list --app <app-id> --json

If you already know the endpoint, use --url <bridge-url> instead of --app <app-id>.

The CLI resolves connections in this order:

  • --url
  • --app through the local bridge registry
  • the only mounted bridge, when exactly one is registered

Useful environment variables:

  • EBT_APP, EBT_URL, EBT_TOKEN, EBT_WINDOW, EBT_VIEW, EBT_TIMEOUT
  • ELECTROBUN_BROWSER_TOOLS_APP, ELECTROBUN_BROWSER_TOOLS_URL, ELECTROBUN_BROWSER_TOOLS_TOKEN, ELECTROBUN_BROWSER_TOOLS_WINDOW, ELECTROBUN_BROWSER_TOOLS_VIEW, ELECTROBUN_BROWSER_TOOLS_TIMEOUT

To inspect the built-in mock fixture without a live app:

electrobun-browser-tools doctor --url mock://default --json

Driver Mode

The JavaScript client now covers both inspection and live-driving from the root package entrypoint. Locator actions resolve against the current DOM on each attempt instead of operating on stale snapshot node ids.

import { connect } from 'electrobun-browser-tools'

const driver = await connect({
  url: process.env.EBT_URL,
  timeout: 15_000,
})

const page = driver.page('active')

await page.getByTestId('customer-name').fill('Ada Lovelace')
await page.getByTestId('order-notes').fill('Fragile')
await page.locator('select[data-testid="shipping-speed"]').selectOption('express')
await page.getByRole('radio', { name: /card/i }).check()
await page.getByTestId('accept-terms').check()
await page.getByTestId('reveal-secret').click()
await page.getByTestId('secret-offer').waitFor({ state: 'visible' })
await page.getByTestId('dismiss-promo').click()
await page.waitForRequest(/submit/)
await page.getByTestId('checkout-submit').click()
await page.waitForURL(/#complete$/)

console.log(await page.url())

Current high-level JavaScript surface:

  • connect(options)
  • createCatalogPayload()
  • driver.doctor(), driver.status(), driver.tree()
  • driver.windows(), driver.window(ref).info(), driver.window(ref).focus(), driver.window(ref).screenshot()
  • driver.views(windowRef?)
  • driver.eventsWait(), driver.eventsTail(), driver.eventsSummary()
  • driver.logsTail(), driver.logsSearch(), driver.logsSummary()
  • driver.errorsList(), driver.errorsGet(), driver.errorsWatch()
  • driver.stateList(), driver.stateGet()
  • driver.networkTail(), driver.networkSummary(), driver.networkWait()
  • driver.perfSummary(), driver.perfMarks()
  • driver.compareSnapshots(before, after), driver.exportSnapshot(snapshot)
  • driver.page(ref?)
  • driver.window(ref?)
  • page.locator(selector)
  • page.getByRole(role, { name? })
  • page.getByText(text)
  • page.getByTestId(testId)
  • page.view(), page.devtools(action)
  • page.url(), page.snapshot(), page.screenshot()
  • page.node(), page.hitTest(), page.explain()
  • page.ancestors(), page.descendants()
  • page.query(), page.text(), page.attrs(), page.style(), page.html()
  • page.waitForURL(url)
  • page.waitForEvent(eventName, { match? })
  • page.waitForRequest(url, { match? })
  • page.waitForResponse(url, { match? })
  • locator.filter({ has, hasText, visible })
  • locator.first(), locator.nth(index)
  • locator.resolve(), locator.count()
  • locator.textContent(), locator.innerHTML(), locator.isVisible(), locator.boundingBox()
  • locator.waitFor({ state })
  • locator.click(), locator.fill(), locator.clear(), locator.press()
  • locator.focus(), locator.blur(), locator.hover()
  • locator.check(), locator.uncheck(), locator.selectOption()

Action helpers accept timeout, and mutating locator actions also accept force when you need to bypass visibility or occlusion checks.

CLI Driver Commands

The CLI now exposes the same live-driving capabilities in a bash-friendly form.

Page-scoped commands:

  • page view
  • page snapshot
  • page screenshot
  • page url
  • page resolve <targetRef>
  • page count <targetRef>
  • page text-content <targetRef>
  • page inner-html <targetRef>
  • page is-visible <targetRef>
  • page bounding-box <targetRef>
  • page click <targetRef>
  • page fill <targetRef> <value>
  • page clear <targetRef>
  • page press <targetRef> <key>
  • page focus <targetRef>
  • page blur <targetRef>
  • page hover <targetRef>
  • page check <targetRef>
  • page uncheck <targetRef>
  • page select-option <targetRef> <value> or --values a,b
  • page wait-for <targetRef>
  • page wait-for-url <matcher>
  • page wait-for-event <eventName>
  • page wait-for-request <matcher>
  • page wait-for-response <matcher>

Window-scoped alias:

  • window screenshot

Example flow:

electrobun-browser-tools page fill testid:customer-name "Ada Lovelace" --app <app-id> --json
electrobun-browser-tools page select-option testid:shipping-speed express --app <app-id> --json
electrobun-browser-tools page check testid:accept-terms --app <app-id> --json
electrobun-browser-tools page click testid:reveal-secret --app <app-id> --json
electrobun-browser-tools page wait-for testid:secret-offer --state visible --app <app-id> --json
electrobun-browser-tools page wait-for-request '/customer=Ada/' --app <app-id> --json
electrobun-browser-tools page click testid:checkout-submit --app <app-id> --json
electrobun-browser-tools page wait-for-url '*#complete' --app <app-id> --json
electrobun-browser-tools page text-content testid:summary-output --app <app-id> --json

CLI page commands use live locator refs:

  • css:button[data-testid="checkout-submit"]
  • testid:checkout-submit
  • role:button
  • role:button:Place order
  • text:Place order

node: refs are intentionally rejected for driver actions because they come from snapshots and are not stable live targets.

For more complex locator composition, target-based page commands also accept:

  • --scope or --within
  • --has
  • --has-text
  • --first
  • --nth
  • --visible true|false
  • --locator-json '{"kind":"role","role":"button","filters":[{"visible":true}]}'

Action commands support --timeout, and mutating commands also support --force.

Common Refs

Window refs:

  • active
  • id:2
  • title:Checkout

View refs:

  • active
  • id:21
  • host:11
  • url:*checkout*

Target refs for layout and DOM inspection:

  • node:n12
  • css:button[data-testid="checkout-submit"]
  • testid:checkout-submit
  • role:button
  • role:button:Place order
  • text:Place order

Most layout and DOM commands can reuse a cached snapshot with --snapshot <snapshot-id>.

Capabilities And Limits

  • Sandboxed views remain partial. They can expose events and metadata, but live DOM inspection and DOM-based driver actions require a DOM-capable view.
  • Screenshot capture is runtime-specific. Built-in Electrobun screenshot support currently targets the visible on-screen region instead of full-page content.
  • The built-in Electrobun screenshot path is currently tied to the default electrobun/bun runtime on macOS.
  • page.screenshot() and window.screenshot() route through the existing capture layer, so unsupported platforms and runtimes still fail explicitly rather than silently degrading.
  • page.waitForRequest() and page.waitForResponse() use the bridge's in-page network instrumentation, so they depend on mounted instrumentation rather than generic browser devtools parity.
  • unsafe.evaluate() is intentionally not part of the first stable driver surface.

Run doctor --json to inspect both legacy capability booleans and the richer detailed capability flags exposed by the bridge.

Lower-Level APIs

If you need a custom adapter or want to mount the bridge yourself, the lower-level APIs are still available:

  • createToolBridge(options)
  • mountToolBridge(options)
  • mountElectrobunToolBridge(options)

mountElectrobunToolBridge(...) accepts the lower-level bridge options too, including host, port, path, buffer sizes, capabilities, and getRecent.

Apps still own domain-specific state. Use the bridge state option to expose that cleanly:

await mountElectrobunToolBridge({
  mainWindow,
  state: {
    workspace: () => ({
      cwd: process.cwd(),
      branch: currentBranch,
    }),
    sessions: () => ({
      activeSessionId,
      total: sessions.length,
    }),
  },
})

Testing

The repo now validates the driver and inspection surfaces with:

  • protocol and capability registry tests
  • subprocess CLI tests
  • typed JavaScript client and driver API tests
  • a live Bun-hosted Electrobun runtime fixture
  • a live Electron fixture through the lower-level bridge API

Useful local checks:

bun run typecheck
bun run build
bun run test