Standard Toolkit
Packages@accelint/bus

Broadcast

Event bus for emitting and listening to events across browser contexts using the BroadcastChannel API.

Usage

import { Broadcast, Payload } from '@accelint/bus';

type AppEvents = Payload<'user:login', { userId: string }>;

const bus = Broadcast.getInstance<AppEvents>();

// Listen for events
bus.on('user:login', (event) => {
  console.log('User logged in:', event.payload.userId);
});

// Emit events
bus.emit('user:login', { userId: '123' });

Reference

Type Parameters

  • Events - Union type of all event payloads. Should be a union of Payload<type, data> types.

Constructor

constructor(config?: BroadcastConfig)

Creates a new Broadcast instance. For most cases, use getInstance() instead to access the singleton.

Parameters:

ParameterTypeDescription
configBroadcastConfigOptional configuration object
config.channelNamestringName of the BroadcastChannel (default: '@accelint/bus')

Static Methods

getInstance

static getInstance<T extends BasicPayload>(config?: BroadcastConfig): Broadcast<T>

Returns the singleton Broadcast instance. Creates the instance on first call.

Good to know: Broadcast uses a singleton pattern. Multiple calls to getInstance() return the same instance, ensuring events are shared across your entire application.

Event Methods

on

on<Type extends Events['type']>(
  type: Type,
  callback: (data: ExtractEvent<Events, Type>) => void
): () => void

Registers a callback for the specified event type. Returns an unsubscribe function.

Parameters:

ParameterTypeDescription
typeType extends Events['type']The event type to listen for
callback(data: ExtractEvent<Events, Type>) => voidFunction called when event is received

Returns: Unsubscribe function to remove the listener

once

once<Type extends Events['type']>(
  type: Type,
  callback: (data: ExtractEvent<Events, Type>) => void
): () => void

Like on, but the callback is automatically removed after being invoked once.

off

off<Type extends Events['type']>(
  type: Type,
  callback: (data: ExtractEvent<Events, Type>) => void
): void

Unregisters a specific callback for an event type.

emit

emit<Type extends Events['type']>(
  type: Type,
  payload: Data,
  options?: EmitOptions
): void

Emits an event to all listening contexts.

Parameters:

ParameterTypeDescription
typeType extends Events['type']The event type
payloadDataEvent payload (must be serializable via structured clone algorithm)
optionsEmitOptionsOptional delivery options
options.target'self' | 'others' | 'all' | UniqueIdTarget delivery scope (default: 'self')

Configuration Methods

setEventEmitOptions

setEventEmitOptions(type: Events['type'], options: EmitOptions | null): void

Sets default emit options for a specific event type. These options are merged with global and local options (global < event < local precedence).

setEventsEmitOptions

setEventsEmitOptions(events: Map<Events['type'], EmitOptions | null>): void

Sets emit options for multiple events at once.

setGlobalEmitOptions

setGlobalEmitOptions(options: EmitOptions | null): void

Sets default emit options for all events. Lowest precedence in the merge hierarchy.

Management Methods

deleteEvent

deleteEvent(type: Events['type']): void

Removes all listeners and configuration for a specific event type.

destroy

destroy(): void

Closes the BroadcastChannel and cleans up all listeners. After calling this, the instance is no longer usable.

ping

ping(): void

Sends a ping to discover other Broadcast instances. Updates the connected property with responding instance IDs.

Good to know: Due to the event-driven nature of ping/echo, this is neither synchronous nor awaitable. Listen for ping/echo events and update UI reactively to reflect the current state of the connected property.

Properties

id

readonly id: UniqueId

Read-only unique identifier for this Broadcast instance.

connected

readonly connected: ReadonlySet<UniqueId>

Read-only set of IDs for other Broadcast instances currently communicating with this one. Updated when instances ping/echo or disconnect.

Examples

Example: Basic pub/sub

import { Broadcast, Payload } from '@accelint/bus';

type Events = Payload<'message', { text: string }>;

const bus = Broadcast.getInstance<Events>();

// Subscribe
const unsubscribe = bus.on('message', (event) => {
  console.log(event.payload.text);
});

// Publish
bus.emit('message', { text: 'Hello!' });

// Later: cleanup
unsubscribe();

Example: One-time listener

import { Broadcast, Payload } from '@accelint/bus';

type Events = Payload<'init:complete'>;

const bus = Broadcast.getInstance<Events>();

bus.once('init:complete', () => {
  console.log('App initialized'); // Only fires once
});

bus.emit('init:complete');
bus.emit('init:complete'); // Callback not called

Example: Targeting specific instances

import { Broadcast, Payload } from '@accelint/bus';

type Events = Payload<'sync', { data: unknown }>;

const bus = Broadcast.getInstance<Events>();

// Emit only to self (default)
bus.emit('sync', { data: {} });

// Emit to all including self
bus.emit('sync', { data: {} }, { target: 'all' });

// Emit to all others (not self)
bus.emit('sync', { data: {} }, { target: 'others' });

// Emit to specific instance by ID
const targetId = '...'; // Another bus instance ID
bus.emit('sync', { data: {} }, { target: targetId });

Example: Discovering connected instances

import { Broadcast } from '@accelint/bus';

const bus = Broadcast.getInstance();

// Request discovery
bus.ping();

// Listen for connection events
bus.on('__PING__', ({ source }) => {
  console.log(`Discovered instance: ${source}`);
});

bus.on('__ECHO__', ({ source }) => {
  console.log(`Connected to instance: ${source}`);
});

// Check connected instances (after async responses arrive)
setTimeout(() => {
  console.log(`Connected instances: ${bus.connected.size}`);
  for (const id of bus.connected) {
    console.log(`- ${id}`);
  }
}, 100);

Example: Event-specific options

import { Broadcast, Payload } from '@accelint/bus';

type Events =
  | Payload<'local', { data: string }>
  | Payload<'broadcast', { data: string }>;

const bus = Broadcast.getInstance<Events>();

// Configure 'local' to only emit to self
bus.setEventEmitOptions('local', { target: 'self' });

// Configure 'broadcast' to emit to all including self
bus.setEventEmitOptions('broadcast', { target: 'all' });

// Now all 'local' emits stay local
bus.emit('local', { data: 'private' }); // Only this instance receives

// 'broadcast' emits to all instances
bus.emit('broadcast', { data: 'public' }); // All instances receive

Example: Cleanup on destroy

import { Broadcast } from '@accelint/bus';

const bus = Broadcast.getInstance();

bus.on('some-event', () => {
  // Handler logic
});

// Later: clean up completely
bus.destroy();

// After destroy, bus is unusable
// Calling getInstance() will create a new instance

Good to know: Events emitted via Broadcast are delivered using the structured clone algorithm. This means payloads must be serializable—functions, DOM nodes, and symbols cannot be sent.

On this page