hubcap bridge

Persistent bidirectional message channel between the CLI and client-side JavaScript.

When to use

Use bridge when you need two-way communication with JavaScript running in a page. The command stays alive, streaming messages as LDJSON over stdio. This is useful for syncing data with a web app’s client-side API, driving interactive page workflows, or building real-time integrations.

Usage

hubcap bridge <script>
hubcap bridge --file <file>

The script receives two variables in scope:

  • messages — async iterator of messages sent from stdin
  • send(data) — function to send a message to stdout

Arguments

ArgumentTypeRequiredDescription
scriptstringYes (or --file)JavaScript to run in the page context

Flags

FlagTypeDefaultDescription
--filestringLoad JavaScript from a file instead of inline

Protocol

stdout (LDJSON)

Each line is a JSON object with a type field:

TypeFieldsDescription
readyBridge established, JS is running
messagedataValue passed to send() from JS
errorerrorUncaught JS error or send failure
closeddataBridge ended (script finished, tab closed, keepalive timeout)

stdin (LDJSON)

TypeFieldsDescription
(default)dataDelivered to the messages async iterator
closetypeGraceful shutdown

stderr

Diagnostics and connection errors.

Keepalive

The bridge sends a heartbeat every 2 seconds. If the JS side misses heartbeats for 6 seconds (e.g. the hubcap process was killed), the async iterator closes automatically.

Errors

ConditionExit codeStderr
Chrome not connected2error: connecting to Chrome: ...
Script injection failed1error: ...
Timeout3error: timeout

Examples

Send a message from JS:

hubcap bridge 'send({title: document.title})'

Echo messages back (stdin → JS → stdout):

echo '{"data":{"n":7}}' | hubcap bridge '
  for await (const msg of messages) {
    send({doubled: msg.n * 2});
    break;
  }
'

Sync with a page API:

hubcap bridge --file sync.js --target "$TAB"

Where sync.js might be:

for await (const msg of messages) {
  if (msg.action === "get") {
    const data = await window.appAPI.getData(msg.key);
    send({key: msg.key, value: data});
  } else if (msg.action === "set") {
    await window.appAPI.setData(msg.key, msg.value);
    send({key: msg.key, ok: true});
  }
}

See also

  • eval - One-shot JavaScript evaluation
  • run - Run a JavaScript file (one-shot)
  • console - Capture console messages (one-way)