I built a tiny event emitter that fixes a bug most people don't know they have: if a handler calls off() on itself during emit, the next handler gets skipped. EventEmitter3, Node's built-in EventEmitter, and mitt all have this problem.
Zephyr Events uses snapshot-based iteration so handlers can subscribe, unsubscribe, or clear listeners mid-emit without side effects. If you don't need that safety, there's a zephyrEventsFast mode that's up to 82% faster.
1.9KB, zero dependencies, tree-shakeable
Full TypeScript generics with strict handler signatures
Wildcard listeners, shared handler maps, unsubscribe functions
ESM, CommonJS, and UMD builds
import zephyrEvents from 'zephyr-events';
type Events = {
'user:login': { id: number; name: string }
'error': Error
}
const emitter = zephyrEvents<Events>();
const unsub = emitter.on('user:login', (user) => {
console.log(`Welcome, ${user.name}`);
});
emitter.emit('user:login', { id: 1, name: 'Alice' });
unsub();
https://www.npmjs.com/package/zephyr-events
Would love feedback, especially on the API design and whether the safe/fast split makes sense as a default.
Top comments (0)