Wanderland

Lantern Bus

window.lanternBus — a tiny pub/sub layer on top of document custom events. Any script or component can register for a named event; any other can fire it. The bus adds listener counting and metadata on top of the plain addEventListener substrate so feature-detection UIs can reactively surface controls only when a handler is present.

File

lantern/public/js/lantern-bus.js

API

Method Purpose
on(name, handler, { meta } = {}) Register. Returns an unsubscribe function.
off(name, handler) Unregister.
emit(name, detail) Fire a CustomEvent(name, { detail }) on document.
hasListeners(name) True if at least one bus-registered handler exists.
listeners(name) [{ meta }, ...] — inspect who's listening (registration objects, no handlers exposed).

Plain document.addEventListener / dispatchEvent remain compatible — they just aren't counted. Migrate to bus.on when introspection matters.

Feature detection

Components render conditional chrome based on who else is on the page.

if (window.lanternBus.hasListeners('transfer-to-sidebar')) {
  // Another component is listening — surface the "move to sidebar" button.
}

Meta-events bus:listener-added and bus:listener-removed fire on every registration change, letting UIs stay in sync without polling.

Signal routing convention

When a wanderland-core pipeline emits a :signals:web:<action> crossing, the initiating component walks the response's events array, strips the :signals:web: prefix, and calls bus.emit(action, payload). See wanderland-web-signals for the full contract and receiver library.

for (const ev of response.events || []) {
  if (!ev.type_addr.startsWith(':signals:web:')) continue;
  const name = ev.type_addr.slice(':signals:web:'.length);
  window.lanternBus.emit(name, ev.payload);
}

Every subscriber for name receives the payload. The payload carries whatever routing the action needs (target element id, slug, section, message body, form fields). No component owns the action namespace — receivers self-register and decide what a given action means.

Tracking case