# @lensmcp/client-runtime

The browser-side capture layer for LensMCP. It connects to the
[`@lensmcp/bridge`](../bridge) WebSocket and streams one envelope per
observed event — `window.onerror` / `unhandledrejection`, `console.*`,
`fetch` timing, and History API route changes — plus a
`window.__LENSMCP_PUBLISH__` hook that in-page instrumentation
(`@lensmcp/react-instrumentation`, `@lensmcp/valtio-instrumentation`) rides.

It is **strictly passive**: it never mutates app state, swallows errors, or
changes scheduling.

## No-build install

For any host **without** a LensMCP build plugin — webpack, Next.js, or no
bundler at all — import the side-effecting entry at your app's top level:

```ts
import '@lensmcp/client-runtime/auto';
```

It resolves the bridge WebSocket endpoint **at runtime**, so nothing needs to
bake the URL in at build time. Resolution order:

1. `globalThis.__LENSMCP_WS_URL__` — a full `ws://…` URL
2. `<meta name="lensmcp-ws" content="ws://…">`
3. `ws://<host>:<port>` from `__LENSMCP_WS_HOST__` / `<meta name="lensmcp-ws-host">` /
   `location.hostname` and `__LENSMCP_WS_PORT__` / `<meta name="lensmcp-ws-port">` /
   the default port (`5747`)

Run the bridge alongside your dev server:

```bash
lensmcp bridge            # ws://127.0.0.1:5747, forwards to .lensmcp/events.jsonl
```

The bridge admits pages by **origin**: loopback dev servers (`localhost`,
`127.0.0.1`, `*.localhost`) work as-is; a page served from any other host — a
custom `/etc/hosts` name, a LAN address — needs its origin in
`LENSMCP_BRIDGE_ALLOWED_ORIGINS` where the bridge runs. If the bridge was
started with `LENSMCP_BRIDGE_TOKEN`, give the page the same value:

```html
<meta name="lensmcp-ws-token" content="…">
<!-- or: <script>window.__LENSMCP_WS_TOKEN__ = '…'</script> before the runtime loads -->
```

For explicit control, call the installer yourself instead of importing `/auto`:

```ts
import { installLensmcp } from '@lensmcp/client-runtime';

installLensmcp({ wsUrl: 'ws://127.0.0.1:5747' });
// against a bridge started with LENSMCP_BRIDGE_TOKEN: installLensmcp({ wsUrl: '…', wsToken: '…' })
```

## With a build plugin

When `@lensmcp/vite-plugin` (or another LensMCP host adapter) is active it
injects an equivalent runtime for you with the bridge port already wired —
you don't import anything.
