Version v3.0.0 Size 1.4 KB gzip Dependencies Zero dependencies
Why Herald?
Raw event emitters lose payload inference and leave one-shot waiting, cancellation, diagnostics, and teardown to every caller. Herald keeps events temporal: use Ripple when you need retained state.
ts
// Before
const listeners = new Set<(payload: unknown) => void>();
listeners.add((payload) => loadProfile((payload as { id: string }).id));
// After
import { createBus } from '@vielzeug/herald';
interface AppEvents {
'user:login': { id: string };
}
function loadProfile(id: string): void {
console.log(id);
}
const bus = createBus<AppEvents>();
bus.on('user:login', ({ id }) => loadProfile(id));Delivery is synchronous and temporal: events are not retained or replayed. Listener failures do not stop later listeners; emit() rethrows the first failure after dispatch, while tap() exposes every failure for diagnostics.
| Feature | Herald | mitt | EventEmitter3 |
|---|---|---|---|
| Bundle size | 1.4 KB | ~200 B | ~1.5 kB |
| Typed payloads | |||
| One-shot async wait | |||
| AbortSignal lifecycle | |||
| Runtime activity tracing | |||
| Zero dependencies |
Use Herald when modules need typed temporal event delivery with owned lifecycle.
Consider Ripple when consumers need current state and replayed values.
Installation
sh
pnpm add @vielzeug/heraldsh
npm install @vielzeug/heraldsh
yarn add @vielzeug/heraldQuick Start
ts
import { createBus } from '@vielzeug/herald';
interface AppEvents {
'user:login': { id: string };
'user:logout': void;
}
const bus = createBus<AppEvents>();
const stop = bus.on('user:login', ({ id }) => console.log(id));
bus.emit('user:login', { id: '42' });
stop();
bus.dispose();Features
on()/once()— typed subscriptions with explicit teardownonAny()— cross-cutting event observationtap()— observe bus activity for logging and diagnosticswait()/waitAny()— one-shot async coordinationlistenerCount()/wildcardCount()/eventNames()— listener inspectionerrortap events — isolate listener failures without interrupting deliveryAbortSignal— subscription, wait, tap, and disposal ownershipcreateTestBus()— emitted-payload recording for tests