Files
2026-05-27 23:29:53 +01:00

76 lines
3.7 KiB
Markdown

# `@suaveplan/events` v1.1.0 — Port Missing Capabilities from Suaveplan
**Status:** Active
**Target:** `@suaveplan/events` 0.0.0 → additive capabilities, no breaking changes
**Source:** `/home/ubuntu/web/suaveplan/openspec/changes/events-v1.1.0/`
---
## Why
The genesis `EventBus` was a cut-down redesign of suaveplan's `EventEmitter`. While it introduced improvements (interceptor API, `BoundedQueue`, idempotent listeners, deterministic injection), it was missing several capabilities that suaveplan had already proven necessary:
- No event buffering for late subscribers — plugins attaching after lifecycle transitions miss historical events.
- No wildcard pattern matching — observers must enumerate every event name.
- No async iteration — consumers manually manage `on`/`off` instead of `for await`.
- No `prependListener` — impossible to insert a listener at the head.
- No listener introspection — `listeners()` / `listenerCount()` absent.
- No `once()` → `off()` round-trip — `off(type, originalListener)` fails for `once` registrations.
- No concurrency control on `emitAsync` — one slow listener blocks the chain.
- No `maxListeners` warning — memory leaks go undetected.
- No global `errorSink` — caller must inspect `EmitResult.errors` or errors are lost.
- No `Symbol.dispose` — no RAII cleanup via `using`.
These gaps force consumers to reinvent the missing primitives downstream.
---
## What changes
### Core `EventBus` additions
1. **`bufferSize` option** — replays the last N events to subscribers that attach after emission.
2. **`wildcard` option** — subscribe to `plugin:*` and match all `plugin:ready`, `plugin:error`, etc.
3. **`iter(type, signal?)`** — async iterable over events, compatible with `for await`.
4. **`prepend(type, listener)`** — insert listener at the head of the dispatch queue.
5. **`listeners(type)` / `listenerCount(type)`** — introspection without exposing internals.
6. **`offAll(type?)`** — remove all listeners for a type, or everything.
7. **`once()` WeakMap tracking** — `off(type, originalListener)` works for `once` registrations.
8. **`concurrency` option on `emitAsync`** — `sequential` (default), `parallel`, `allSettled`.
9. **`maxListeners` + `errorSink`** — warnings and centralised error routing.
10. **`Symbol.dispose`** on `EventBus` and `Unsubscribe` handles.
11. **`EVENTS.LISTENER.MAX_EXCEEDED`** error code.
### Non-goals
- No breaking changes to existing `EventBus` API.
- No `BoundedQueue` integration into `EventBus` dispatch — remains a standalone utility.
- No changes to companion packages (`events-otel`, `events-schema`, `events-metrics`, `events-transport`) unless required by API additions.
---
## Impact
### Affected dependents
Run `bunx turbo ls --filter=...@suaveplan/events` to enumerate. All additive surface, so no downstream code changes required. Verified by running downstream test suites.
- `@suaveplan/crypto-vault` — no action needed (uses `EventBus` directly, doesn't touch changed surface)
- `@suaveplan/network` — no action needed (uses `EventBus` + `BoundedQueue`, unchanged)
- `@suaveplan/storage` — no action needed
- `@suaveplan/packer` — no action needed
- `@suaveplan/fsm` — no action needed
- `@suaveplan/retry` — no action needed
- `@suaveplan/migration` — no action needed (type-only import)
- `@suaveplan/config` — no action needed
- `@suaveplan/events-schema` — no action needed (type-only import)
- `@suaveplan/events-metrics` — no action needed (type-only import)
- `@suaveplan/events-otel` — no action needed (type-only import)
- `@suaveplan/events-transport` — no action needed (type-only import)
---
## Migration
No migration needed — purely additive.