Commiq Docs
Plugins

Devtools React

Devtools React

@naikidev/commiq-devtools provides an embedded devtools panel for your applications. Drop it into your app to inspect events, trace causality, view state, and monitor performance — no browser extension required.

Installation

pnpm add @naikidev/commiq-devtools
npm install @naikidev/commiq-devtools
yarn add @naikidev/commiq-devtools
bun add @naikidev/commiq-devtools

Peer dependencies: @naikidev/commiq, react, react-dom.

Basic Usage

No provider required. Pass stores directly as props or mount imperatively.

As a Component

import { CommiqDevtools } from "@naikidev/commiq-devtools";
import { counterStore } from "./stores/counter";
import { todoStore } from "./stores/todos";

function App() {
  return (
    <>
      <YourApp />
      <CommiqDevtools
        stores={{ counter: counterStore, todos: todoStore }}
      />
    </>
  );
}

Without JSX

Mount from anywhere — main.ts, a store file, or a plain script:

import { mountDevtools } from "@naikidev/commiq-devtools";
import { counterStore } from "./stores/counter";
import { todoStore } from "./stores/todos";

const unmount = mountDevtools({
  stores: { counter: counterStore, todos: todoStore },
});

// Later, to remove:
unmount();

Both approaches render a floating button in the corner of the screen. Click it to open the devtools panel.

Props

PropTypeDefaultDescription
storesRecord<string, SealedStore<any>>(required)Stores to monitor, keyed by display name
enabledbooleanauto-detecttrue = always show, false = never show, undefined = hide in production
position"bottom-left" | "bottom-right" | "top-left" | "top-right""bottom-right"Position of the floating trigger button
initialOpenbooleanfalseWhether the panel starts open
maxEventsnumber500Maximum events kept in the timeline ring buffer
panelHeightnumber360Panel height in pixels
buttonStyleCSSPropertiesAdditional styles for the trigger button

Features

Events Tab

Linear event log showing all store activity. Filter by store or toggle built-in events. Click any row to expand details including event data and state diffs.

Causality Graph

Hierarchical tree view of command causality chains. See which commands triggered other commands and events, with expandable detail panels.

Timeline

Visual SVG timeline with per-store swimlanes. Events appear as dots connected by causality links. Zoom with scroll, pan by dragging.

Performance

Aggregated command metrics: total/average/min/max duration per command type, with visual bar charts. Sort by total time, average time, max time, or call count.

State

Current state of each connected store displayed as a collapsible JSON tree.

Dependency Map

Force-directed graph showing inter-store dependencies. Nodes represent stores, edges show command flows between them with call counts.

Production Gating

By default, CommiqDevtools auto-detects the environment and renders nothing in production. Override this with the enabled prop:

// Always show (e.g., staging environment)
<CommiqDevtools stores={stores} enabled={true} />

// Never show
<CommiqDevtools stores={stores} enabled={false} />

// Auto-detect (default) — hidden when NODE_ENV === "production"
<CommiqDevtools stores={stores} />

Custom Devtools UI

Use the useDevtoolsEngine hook to build your own devtools interface:

import { useDevtoolsEngine } from "@naikidev/commiq-devtools";

function MyDevtools() {
  const engine = useDevtoolsEngine({ counter: counterStore });

  return (
    <div>
      <p>Events: {engine.eventCount}</p>
      <ul>
        {engine.timeline.map((entry) => (
          <li key={entry.correlationId}>{entry.name}</li>
        ))}
      </ul>
    </div>
  );
}

The hook returns a DevtoolsEngine with:

PropertyTypeDescription
timelineTimelineEntry[]All collected events
getChain(correlationId: string) => TimelineEntry[]Events linked by causality
getStateHistory(storeName: string) => StateSnapshot[]State changes over time
storeStatesRecord<string, unknown>Current state of each store
storeNamesstring[]Connected store names
eventCountnumberTotal events collected
clear() => voidReset collection

Export and Import

The devtools panel includes export/import buttons. Export saves the current timeline as a JSON file. Import loads a previously exported timeline for offline inspection.

On this page