Skip to content

Bridge Buses Explicitly ​

Problem ​

Selected events from one bus must be forwarded to another with visible transformation and lifecycle ownership.

Solution ​

Register an ordinary source listener and emit on the target. Its unsubscribe function is the bridge teardown.

ts
import { createBus } from '@vielzeug/herald';

type AppEvents = {
  'user:login': { userId: string };
};

type AuditEvents = {
  'audit:login': { subject: string };
};

const appBus = createBus<AppEvents>();
const auditBus = createBus<AuditEvents>();
const controller = new AbortController();

const bridgeSignal = AbortSignal.any([auditBus.disposalSignal, controller.signal]);
const stopBridge = appBus.on(
  'user:login',
  ({ userId }) => auditBus.emit('audit:login', { subject: userId }),
  { signal: bridgeSignal },
);

appBus.emit('user:login', { userId: '42' });
stopBridge();
appBus.dispose();
auditBus.dispose();

For identical event maps, forwarding remains explicit:

ts
const stop = source.on('user:login', (payload) => target.emit('user:login', payload));

Pitfalls ​

  • Forwarding is synchronous and unbuffered.
  • Bind the bridge to the target's disposalSignal; combine it with any external owner signal using AbortSignal.any().
  • A forwarding listener can create cycles. Keep the event graph directed.
  • Transform payloads explicitly when source and target event types differ.