Event bus
import { createEventBus } from "mountly/bus";createEventBus() gives independent widgets a shared event channel without importing each other or committing to one framework’s store.
Basic usage
Section titled “Basic usage”type CartEvents = { "cart:changed": { count: number }; "product:selected": { sku: string };};
const bus = createEventBus<CartEvents>();
const off = bus.on("cart:changed", (payload) => { console.log(payload.count);});
bus.emit("cart:changed", { count: 3 });off();The generic type is compile-time only. Runtime validation is optional.
Namespaces
Section titled “Namespaces”const cartBus = createEventBus<{ changed: { count: number };}>({ namespace: "cart",});
cartBus.eventName("changed"); // "cart:changed"cartBus.emit("changed", { count: 1 });Namespaces are useful when several teams or bundles share the same page. They keep short event names readable without making global event names ambiguous.
Payload validation
Section titled “Payload validation”const bus = createEventBus<{ selected: { id: string };}>({ validators: { selected: (payload): payload is { id: string } => typeof payload === "object" && payload !== null && typeof (payload as { id?: unknown }).id === "string", },});
bus.emit("selected", { id: "sku_123" }); // okbus.emit("selected", { id: 123 }); // throwsUse validators at host boundaries where event payloads may come from separately deployed widgets. Keep them simple; the helper accepts any type guard, so you can use a schema library if the host already has one.
Custom target
Section titled “Custom target”By default the bus uses a shared EventTarget inside the mountly module instance. Pass a target when you want browser-level events or test isolation:
const bus = createEventBus<AppEvents>({ target: window, namespace: "mountly",});Related
Section titled “Related”- Cross-framework Event Bus shows the same pattern across React, Vue, and Svelte widgets.