> ## Documentation Index
> Fetch the complete documentation index at: https://empty-ad9a3406.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# EventBus

> Pub/sub event system for plugin communication

## Overview

The EventBus is a simple pub/sub system that enables decoupled communication between plugins.

```javascript theme={null}
api.bus.on('todo:added', (data) => {
  console.log('New todo:', data.text);
});

api.bus.emit('todo:added', { text: 'Buy milk' });
```

## Methods

### `bus.on(event, callback)`

Subscribe to an event. Multiple listeners can subscribe to the same event.

```javascript theme={null}
api.bus.on('theme:changed', (data) => {
  document.body.style.background = data.color;
});
```

| Parameter  | Type       | Description                    |
| ---------- | ---------- | ------------------------------ |
| `event`    | `string`   | Event name                     |
| `callback` | `function` | Handler called with event data |

### `bus.off(event, callback)`

Unsubscribe from an event. Must pass the **same function reference** used in `on()`.

```javascript theme={null}
function handler(data) { /* ... */ }

api.bus.on('my-event', handler);
// later:
api.bus.off('my-event', handler);
```

### `bus.once(event, callback)`

Subscribe to an event, but the listener is automatically removed after the first emission.

```javascript theme={null}
api.bus.once('board:ready', (data) => {
  console.log('Board is ready, only fires once');
});
```

| Parameter  | Type       | Description                                       |
| ---------- | ---------- | ------------------------------------------------- |
| `event`    | `string`   | Event name                                        |
| `callback` | `function` | Handler called once with event data, then removed |

### `bus.emit(event, data)`

Publish an event to all subscribers. Errors in listeners are caught and logged without interrupting other listeners.

```javascript theme={null}
api.bus.emit('todo:added', { text: 'Buy milk', done: false });
```

| Parameter | Type     | Description                   |
| --------- | -------- | ----------------------------- |
| `event`   | `string` | Event name                    |
| `data`    | `any`    | Payload passed to subscribers |

### `bus.removeAll([event])`

Remove all listeners for a specific event, or **all events** if no event name is given.

```javascript theme={null}
// Remove all listeners for a specific event
api.bus.removeAll('todo:added');

// Remove ALL listeners across all events
api.bus.removeAll();
```

| Parameter | Type     | Description                                             |
| --------- | -------- | ------------------------------------------------------- |
| `event`   | `string` | *(Optional)* Event name. If omitted, clears everything. |

<Warning>
  `removeAll()` with no arguments is a nuclear option. Use with care — it removes listeners from every plugin, not just yours.
</Warning>

## Naming Convention

Use `namespace:action` to avoid collisions between plugins:

| ✅ Good                | ❌ Bad    |
| --------------------- | -------- |
| `todo:added`          | `added`  |
| `kanban:card:moved`   | `move`   |
| `theme:changed`       | `change` |
| `sticky-note:created` | `new`    |

## Example: Cross-Plugin Communication

```javascript theme={null}
// === todo-list/plugin.js ===
export function setup(api) {
  const todos = [];

  function addTodo(text) {
    todos.push({ text, done: false });
    api.bus.emit('todo:added', { text, count: todos.length });
  }
}

// === stats/plugin.js ===
export function setup(api) {
  let count = 0;

  api.bus.on('todo:added', (data) => {
    count = data.count;
    renderStats();
  });
}
```

<Warning>
  Plugins should never directly import or reference each other. Always use the event bus for communication.
</Warning>
