Commiq Docs
Plugins

Devtools

Devtools

Commiq includes built-in instrumentation and a devtools package for debugging, event inspection, and state tracking.

Instrumentation

Every event and command in Commiq carries instrumentation metadata automatically:

  • timestampDate.now() when the event was emitted
  • correlationId — unique identifier for each event/command
  • causedBy — links to the parent command or event that triggered this one (null for user-initiated commands)

This enables full causality tracking: you can trace any event back through the chain of commands and events that caused it.

Installation

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

Basic Usage

import { createStore, createCommand } from "@naikidev/commiq";
import { createDevtools } from "@naikidev/commiq-devtools-core";

const store = createStore({ count: 0 });
store.addCommandHandler("increment", (ctx) => {
  ctx.setState({ count: ctx.state.count + 1 });
});

// Connect devtools
const devtools = createDevtools();
devtools.connect(store, "counter");

// Events are now tracked
store.queue(createCommand("increment", undefined));

Query API

Query collected events programmatically at any time:

// Get full event timeline
const timeline = devtools.getTimeline();

// Filter by store
const counterEvents = devtools.getTimeline("counter");

// Get causality chain for an event
const chain = devtools.getChain(someCorrelationId);

// Get state change history
const history = devtools.getStateHistory("counter");

Console Logging

Enable structured console output for quick debugging:

const devtools = createDevtools({ logToConsole: true });
devtools.connect(store, "counter");

// Console output:
// [12:34:56.789] counter | commandStarted a3K9mX7p
// [12:34:56.789] counter | stateChanged b7yP2nX1 (caused by a3K9mX7p)
// [12:34:56.790] counter | commandHandled c1zR4qW8 (caused by a3K9mX7p)
// [12:34:57.001] counter | commandInterrupted d2xT5mQ9 (caused by a3K9mX7p)

Event Classification

Timeline entries are classified by type for filtering and color-coding:

ClassificationEventsColor
CommandcommandStarted, commandHandledIndigo
ErrorcommandHandlingError, invalidCommandRed
InterruptedcommandInterruptedOrange
State changestateChangedAmber
EventCustom events, stateResetGreen

Interruptable commands that are cancelled (either while queued or running) appear as commandInterrupted entries with a phase field ("queued" or "running").

Custom Transports

The default transport uses window.postMessage, which serves as an integration point for external tools. You can provide custom transports for other environments:

import { createDevtools, memoryTransport } from "@naikidev/commiq-devtools-core";

// In-memory transport for testing
const transport = memoryTransport();
const devtools = createDevtools({ transport });
devtools.connect(store, "counter");

// Inspect captured messages
console.log(transport.messages);

Implementing a Custom Transport

import type { Transport, DevtoolsMessage } from "@naikidev/commiq-devtools-core";

const customTransport: Transport = {
  send(message: DevtoolsMessage) {
    // Send to your backend, WebSocket, etc.
  },
  onMessage(handler) {
    // Listen for incoming messages
    return () => {
      /* cleanup */
    };
  },
  destroy() {
    // Clean up resources
  },
};

const devtools = createDevtools({ transport: customTransport });

Options

OptionTypeDefaultDescription
transportTransportwindowMessageTransport()Message transport
maxEventsnumber1000Ring buffer size
logToConsolebooleanfalseLog events to console

Cleanup

// Disconnect a single store
devtools.disconnect("counter");

// Disconnect all stores and clean up
devtools.destroy();

On this page