first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
# events
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Implements the lightweight event bus that powers the queue's
`addEventListener` / `removeEventListener` surface. The emitter keeps a
`Map<StreamEventType, Set<Listener>>` so registration and removal are
both O(1), and exposes a wildcard `"*"` subscription so debugging tools
can observe every event without enumerating types.
## Features
- Concrete-type subscriptions (`chunk:received`, `stream:progress`, …).
- Wildcard subscription via `"*"` that receives every emitted event.
- O(1) add, remove, and emit per listener.
- `clear()` for tear-down (used by `StreamingChunkQueue.clear()`).
## Usage: Basic
```ts
import { StreamEventEmitter } from "@suaveplan/streams-chunk-queue";
const emitter = new StreamEventEmitter();
emitter.addEventListener("chunk:received", (event) => {
console.info("got chunk", event.chunkId);
});
```
## Usage: Advanced
```ts
const wildcard = (event: StreamEvent) =>
telemetry.record("stream.event", { type: event.type });
emitter.addEventListener("*", wildcard);
emitter.removeEventListener("*", wildcard);
```
## API Reference
### `StreamEventEmitter`
- `addEventListener(type, listener)` — register `listener` under
`type` (either a concrete event type or `"*"`).
- `removeEventListener(type, listener)` — remove a previously
registered listener.
- `emit(event)` — dispatch to all matching subscribers, then to all
wildcard subscribers.
- `clear()` — drop every registered listener.
### `WILDCARD_EVENT_TYPE`
The constant `"*"`. Exported so callers don't sprinkle string literals.
## Implementation Notes
The wildcard dispatch happens after concrete dispatch, mirroring the
ordering observable consumers expect (a tracing tool sees the event
after the application code has reacted). Listeners are synchronous —
the bus does not await listener return values; callers that need
async work should `queueMicrotask` inside their listener. The emitter
is intentionally allocation-light: a `Map<type, Set<listener>>` means
add/remove are O(1) and dispatch is O(N) over only the matching
listeners. There is no priority ordering; concrete-type listeners are
dispatched in insertion order, then wildcard listeners in their own
insertion order.