Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/TheSerchCp/SEAM/llms.txt

Use this file to discover all available pages before exploring further.

EventBus is the central nervous system of SEAM’s front-end. It serves two roles simultaneously: an in-process publish/subscribe hub that decouples pages and components from one another, and a transparent bridge that forwards Socket.IO messages from the server into the same event stream. Any part of the application can listen for or emit events without holding a direct reference to the emitter.

Architecture Overview

Internal Pub/Sub

Pages, components, and repositories communicate by emitting named events. Listeners are stored in a Map<string, Set<Function>> so multiple subscribers per event are supported natively.

Socket.IO Bridge

When connect(token) is called, EventBus establishes a Socket.IO connection and re-emits server-side events (operation:progress, data:changed) into the same internal bus. Pages subscribe with EventBus.on() and never interact with the socket directly.

API Reference

on(event, cb)

Registers a listener for the given event name. Returns an unsubscribe function — calling it removes only this specific listener without affecting others on the same event.
event
string
required
The event name to subscribe to (e.g. 'data:changed', 'toast:success').
cb
function
required
Callback invoked with the event payload each time the event is emitted.
// Subscribe and keep a reference to the unsubscribe function
const unsub = EventBus.on('data:changed', (payload) => {
    console.log('Data mutated on server:', payload);
});

// Later — remove only this listener
unsub();

off(event, cb)

Removes a specific callback from an event’s listener set. Prefer the unsubscribe function returned by on() for brevity.
event
string
required
The event name.
cb
function
required
The exact callback reference that was passed to on().
function handleProgress(payload) { /* ... */ }

EventBus.on('operation:progress', handleProgress);
// ...
EventBus.off('operation:progress', handleProgress);

emit(event, payload)

Synchronously invokes all listeners registered for event, passing payload to each.
event
string
required
The event name to publish.
payload
any
Arbitrary data forwarded to every listener.
EventBus.emit('toast:info', { message: 'Syncing…', duration: 2000 });

clearEvent(event)

Removes all listeners for the given event at once. Useful for teardown scenarios where you want to reset an event channel entirely.
event
string
required
The event name whose entire listener set will be deleted.
// Wipe every subscriber for this event
EventBus.clearEvent('operation:progress');

connect(token)

Establishes a Socket.IO connection authenticated with the user’s JWT. Once connected, the socket events operation:progress and data:changed are bridged into the internal bus.
token
string
required
The JWT returned by /auth/login. Used as { auth: { token } } in the Socket.IO handshake.
// Called in main.js after hydrating session from localStorage
if (session.token) EventBus.connect(session.token);
The socket URL is derived from API_BASE by stripping the /api/v1 suffix:
const socketUrl = API_BASE.replace('/api/v1', '');
this._socket = io(socketUrl, { auth: { token } });
connect() guards against double-connections: if a socket is already open it is disconnected before the new one is created.

disconnect()

Closes the Socket.IO connection, nullifies the internal _socket reference, and removes the global data:changed listener that was registered at connect time.
EventBus.disconnect();

socketId (getter)

Returns the current Socket.IO socket ID, or null if not connected. ApiClient reads this value to set the X-Socket-ID request header so the server knows which tab initiated an operation.
console.log(EventBus.socketId); // e.g. "WMmq3n2fLQj4AAAAB"

Bridged Socket Events

These events originate on the server and are re-emitted verbatim into the internal bus by the connect() bridge.

operation:progress

Sent only to the tab that initiated a long-running operation (targeted via X-Socket-ID). Used to drive loading spinners and progress messages.
// Payload shape
{
    operation: string,            // e.g. 'users:create'
    status: 'start' | 'processing' | 'success' | 'error',
    message: string,
    data: any                     // optional result payload
}
EventBus.on('operation:progress', ({ operation, status, message }) => {
    if (status === 'start')      showLoader(message);
    if (status === 'success')    hideLoader();
    if (status === 'error')      showError(message);
});

data:changed

Broadcast to all connected clients when a mutation occurs on the server. Pages subscribe to this event and compare operation against their own interest list to decide whether to re-render.
// Payload shape
{
    operation: string,  // e.g. 'users:update', 'roles:delete'
    data: any           // the mutated resource (optional)
}
import { shouldUpdatePage } from '../core/OperationListeners.js';

EventBus.on('data:changed', ({ operation }) => {
    if (shouldUpdatePage('users', operation)) {
        renderUsersTable();
    }
});

Toast Events

These events are emitted by ApiClient automatically on success and error, and may also be emitted manually anywhere in the application. The global Toast component (initialized in main.js) listens to all four.
EventWhen to use
toast:successMutation completed successfully
toast:errorHTTP error or network failure
toast:warningNon-fatal issue that needs attention
toast:infoNeutral informational message
All toast events share the same payload shape:
// Payload shape for all toast:* events
{
    message: string,    // Text displayed to the user
    duration: number    // Milliseconds before auto-dismiss (e.g. 3000)
}
// Emitted automatically by ApiClient on a successful mutation
EventBus.emit('toast:success', { message: payload.message, duration: 3000 });

// Emitted automatically by ApiClient on HTTP error
EventBus.emit('toast:error',   { message: errorMsg,        duration: 4000 });

// Manual usage from any page or component
EventBus.emit('toast:warning', { message: 'Sin conexión con el servidor', duration: 5000 });

Internal Events

page:reload

An internal signal that can be emitted to request the current page to re-initialize itself without a full route change. Individual pages may listen for this to refresh their data.
EventBus.emit('page:reload', {});

Full Internal Implementation

For reference, the complete bus internals use a Map of Sets — this means the same callback reference can only be registered once per event, preventing accidental duplicate subscriptions from multiple on() calls with the same function.
const _listeners = new Map();

export const EventBus = {
    on(event, cb) {
        if (!_listeners.has(event)) _listeners.set(event, new Set());
        _listeners.get(event).add(cb);

        // Returns unsubscribe function
        return () => this.off(event, cb);
    },

    off(event, cb) {
        _listeners.get(event)?.delete(cb);
    },

    clearEvent(event) {
        _listeners.delete(event);
    },

    emit(event, payload) {
        _listeners.get(event)?.forEach(cb => cb(payload));
    },
    // ...
};

Build docs developers (and LLMs) love