Initial Commit
This commit is contained in:
75
openspec/archive/2026-05-02-events-v1.1.0-port/proposal.md
Normal file
75
openspec/archive/2026-05-02-events-v1.1.0-port/proposal.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# `@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.
|
||||
26
openspec/archive/2026-05-02-events-v1.1.0-port/tasks.md
Normal file
26
openspec/archive/2026-05-02-events-v1.1.0-port/tasks.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Tasks — events v1.1.0 port
|
||||
|
||||
## Core (`@suaveplan/events`)
|
||||
|
||||
- [x] Add `bufferSize` option to `EventBusOptions` — replay buffered events to late subscribers
|
||||
- [x] Add `wildcard` option to `EventBusOptions` — pattern matching on event names
|
||||
- [x] Add `iter(type, signal?)` — async iteration over events
|
||||
- [x] Add `prepend(type, listener)` — prepend listener to dispatch queue
|
||||
- [x] Add `listeners(type)` — return copy of exact-match listeners
|
||||
- [x] Add `listenerCount(type)` — return exact-match listener count
|
||||
- [x] Add `offAll(type?)` — remove all listeners for a type or everything
|
||||
- [x] Fix `once()` → `off()` round-trip via WeakMap tracking
|
||||
- [x] Add `concurrency` option to `EmitAsyncOptions` (`sequential` / `parallel` / `allSettled`)
|
||||
- [x] Add `maxListeners` + `errorSink` to `EventBusOptions`
|
||||
- [x] Add `EVENTS.LISTENER.MAX_EXCEEDED` error code
|
||||
- [x] Implement `Symbol.dispose` on `EventBus` and `Unsubscribe`
|
||||
- [x] Update `event-bus.md` documentation
|
||||
- [x] Add tests for all new capabilities
|
||||
- [x] Type-check and test downstream dependents
|
||||
- [x] Update `openspec/specs/events/spec.md`
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] 100% test coverage maintained on `@suaveplan/events`
|
||||
- [x] All downstream packages that import `@suaveplan/events` compile and test green
|
||||
- [x] No breaking changes to existing public API
|
||||
Reference in New Issue
Block a user