Commiq Docs
Plugins

Devtools

These are the v1 docs. They are not maintained.

This page is a verbatim snapshot of the commiq 1.x documentation, kept for people still running 1.x. It is not corrected and not tested against any release. Several pages contain claims that were wrong when written: examples that do not run as printed, sealStore described as read-only when it was not, handledEvent presented as a working subscription pattern when it never matched, and effects described as swallowing only AbortError when they swallowed everything.

Do not treat anything here as a statement about how commiq 2.x behaves.

What changed in 2.0 and how to upgrade · Current documentation

Site search only indexes the current docs. Use the sidebar to browse these pages.

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