# DevToolsManager

```typescript
class DevToolsManager implements Manager
```

Integrates with [Redux DevTools](https://github.com/reduxjs/redux-devtools) to track
state and [actions](https://dataclient.io/vue/api/Actions.md). Note: does not integrate time-travel.

Add the [chrome extension](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en)
or [firefox extension](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/) to your
browser to get started.

> **Info: implements**
>
> `DevToolsManager` implements [Manager](https://dataclient.io/vue/api/Manager.md)

## constructor(options?, skipLogging?)

### options

[Arguments](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md)
to send to redux devtools.

For example, we can enable the [trace](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md#trace) option to help track down where actions are dispatched from.

```ts title="main.ts"
import { createApp } from 'vue';
import { DataClientPlugin, getDefaultManagers } from '@data-client/vue';
import App from './App.vue';

const managers = getDefaultManagers({
  devToolsManager: { trace: true },
});

const app = createApp(App);
app.use(DataClientPlugin, { managers });
app.mount('#app');
```

### skipLogging

`(action: ActionTypes) => boolean`

Can skip some actions to be registered in the browser devtool.

By default will skip inflight [fetch actions](https://dataclient.io/vue/api/Controller.md#fetch)

```ts title="main.ts"
import { createApp } from 'vue';
import {
  DataClientPlugin,
  DevToolsManager,
  getDefaultManagers,
} from '@data-client/vue';
import App from './App.vue';

// production builds leave out DevToolsManager
const managers = getDefaultManagers({
  devToolsManager: new DevToolsManager(undefined, () => true),
});

const app = createApp(App);
app.use(DataClientPlugin, { managers });
app.mount('#app');
```

#### Skipping high-frequency updates

When using [WebSockets](https://dataclient.io/vue/concepts/managers.md#data-stream) or other real-time data sources,
high-frequency updates can overwhelm the DevTools extension. Use the `predicate` option to
filter out specific action types or schemas:

```ts title="managers.ts"
import { getDefaultManagers, actionTypes } from '@data-client/vue';
import { Ticker } from './resources/Ticker';

const managers = getDefaultManagers({
  devToolsManager: {
    // Increase latency buffer for high-frequency updates
    latency: 1000,
    // Skip WebSocket SET actions for Ticker to reduce log spam
    // (including batched set([Ticker], rows) writes)
    predicate: (state, action) =>
      action.type !== actionTypes.SET ||
      (action.schema !== Ticker && action.schema[0] !== Ticker),
  },
});
```

## Programmatic store access {#controllers}

In development mode, `DevToolsManager` registers each [Controller](https://dataclient.io/vue/api/Controller.md) on
`globalThis.__DC_CONTROLLERS__`, a `Map` keyed by the devtools connection name. It also records the
most recent dispatched actions for each one on `globalThis.__DC_ACTIONS__`, under the same key. This works
in browsers, React Native, and Node, with or without the Redux DevTools extension.

```js title="Browser DevTools console"
// List all registered providers
__DC_CONTROLLERS__.keys();

// Get state from the first provider
__DC_CONTROLLERS__.values().next().value.getState();

// Get state by name
__DC_CONTROLLERS__.get('Data Client: My App').getState();

// Last 10 actions, including the ones dispatched while the page loaded
__DC_ACTIONS__.get('Data Client: My App').slice(-10);
```

This is useful for AI coding assistants using the [Chrome DevTools MCP](https://developer.chrome.com/blog/chrome-devtools-mcp)
or [Expo MCP](https://docs.expo.dev/eas/ai/mcp/) to programmatically inspect and interact
with the store. Each installed [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin.md) registers independently, so
multiple apps on the same page are supported. When a name is already taken, the next one
registers as `'Data Client: My App (2)'`, and so on; set `name` to give each a recognizable key. Where there is no `window`, as when
server rendering, a store replaces the previous one with its name instead, since per-request stores are never cleaned up.

The action log keeps up to twice [`maxAge`](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md#maxage)
actions (100 by default) and skips the same duplicate fetches the extension does. To keep its memory small, only the
newest 20 actions keep their `args` and `response`; older ones keep `type`, `key`, `endpoint`, `meta` and error
responses. While an endpoint [polls](https://dataclient.io/rest/api/RestEndpoint.md#pollfrequency), the log keeps only its last
`maxPollingActions` actions for each key (endpoint and args) (4 by default, the last two polls), so polling doesn't push everything else out:

```ts title="main.ts"
import { createApp } from 'vue';
import { DataClientPlugin, getDefaultManagers } from '@data-client/vue';
import App from './App.vue';

const managers = getDefaultManagers({
  devToolsManager: { maxPollingActions: 10 },
});

const app = createApp(App);
app.use(DataClientPlugin, { managers });
app.mount('#app');
```

Controllers and their logs are removed when `cleanup()` is called. None of this exists in production builds.

## More info

Using this Manager allows in browser [debugging and store inspection](https://dataclient.io/vue/getting-started/debugging.md).
