Commiq Docs
Examples

Event Stream

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.

Event Stream

Every store exposes a real-time stream of all events it emits โ€” builtin and custom. This is useful for debugging, logging, analytics, or building reactive UIs that respond to any store activity.

The API

// Subscribe
const listener = (event: StoreEvent) => {
  console.log(event.name, event.data);
};

store.openStream(listener);

// Unsubscribe
store.closeStream(listener);

Builtin Events

Every command processed by a store emits a sequence of builtin events:

Error cases:

Example: Real-Time Event Log

Subscribing to multiple stores

import type { StoreEvent } from "@naikidev/commiq";

interface LogEntry {
  storeName: string;
  eventName: string;
  data: unknown;
  time: string;
}

function createStreamLogger(
  stores: Record<string, SealedStore<any>>,
  onEntry: (entry: LogEntry) => void,
) {
  const listeners: Array<{
    store: SealedStore<any>;
    listener: (e: StoreEvent) => void;
  }> = [];

  for (const [name, store] of Object.entries(stores)) {
    const listener = (event: StoreEvent) => {
      onEntry({
        storeName: name,
        eventName: event.name,
        data: event.data,
        time: new Date().toISOString(),
      });
    };
    store.openStream(listener);
    listeners.push({ store, listener });
  }

  // Return cleanup function
  return () => {
    for (const { store, listener } of listeners) {
      store.closeStream(listener);
    }
  };
}

React component

function EventStreamViewer() {
  const [entries, setEntries] = useState<LogEntry[]>([]);

  useEffect(() => {
    const cleanup = createStreamLogger(
      { counter: counterStore, todo: todoStore },
      (entry) => setEntries((prev) => [...prev.slice(-200), entry]),
    );
    return cleanup;
  }, []);

  return (
    <table>
      <thead>
        <tr>
          <th>Time</th>
          <th>Store</th>
          <th>Event</th>
          <th>Data</th>
        </tr>
      </thead>
      <tbody>
        {entries.map((e, i) => (
          <tr key={i}>
            <td>{e.time}</td>
            <td>{e.storeName}</td>
            <td>{e.eventName}</td>
            <td>{JSON.stringify(e.data)}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

Filtering by event type

import { builtinEvents } from "@naikidev/commiq";

store.openStream((event) => {
  // Only state changes
  if (event.id === builtinEvents.stateChanged.id) {
    console.log("State:", event.data.prev, "โ†’", event.data.next);
  }

  // Only errors
  if (event.id === builtinEvents.commandHandlingError.id) {
    reportError(event.data.error);
  }
});

Use Cases

Use CaseApproach
Dev toolsLog all events to console or a debug panel
AnalyticsTrack specific events and send to an analytics service
Undo/RedoRecord stateChanged events and replay prev states
Cross-store syncUse openStream directly (or event bus) to react to other stores
TestingAssert that specific events were emitted during a command

On this page