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,78 @@
# SpritePlayerEvents
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`SpritePlayerEvents` is the typed event surface a `SpritePlayer` exposes for downstream consumers — analytics, UI feedback, observability sinks, debug overlays. It is a thin facade over `@suaveplan/events`'s `EventBus`, narrowed to the five event names the player can emit.
The class is intentionally write-internal / read-external: the player constructs it and emits, consumers subscribe and never emit. The internal `EventBus` is not exposed so consumers cannot dispatch arbitrary events through the player's surface, which keeps the contract auditable.
## Features
- Five typed event names: `play`, `stop`, `complete`, `voice-stolen`, `error`.
- Strongly-typed `on` returning an unsubscribe closure — no string-typed payloads at the call site.
- `clear()` wipes all listeners — used by `SpritePlayer.dispose()` to break consumer-to-player references.
- Backed by `@suaveplan/events.EventBus` so payloads flow through the same FIFO dispatch used elsewhere in the platform.
## Usage: Basic Example
```ts
import { createSpritePlayer } from "@suaveplan/audio-sprite-player";
const player = createSpritePlayer({ adapter });
const off = player.events.on("play", (e) => {
console.log(`play ${e.entryName} (${e.handleId}) at ${e.startedAt}`);
});
// ...later
off();
```
## Usage: Advanced Example
```ts
import { createSpritePlayer } from "@suaveplan/audio-sprite-player";
const player = createSpritePlayer({ adapter });
const offs = [
player.events.on("voice-stolen", (e) => {
metrics.voicesStolen.add(1, { entry: e.entryName });
}),
player.events.on("complete", (e) => {
histograms.playMs.record(e.durationMs, { entry: e.entryName });
}),
player.events.on("error", (e) => {
log.error("sprite playback failed", {
handleId: e.handleId,
code: e.code,
message: e.message,
});
}),
];
return () => offs.forEach((off) => off());
```
## API Reference
### `class SpritePlayerEvents`
- `on(event, listener): () => void` — subscribes, returns the unsubscribe closure.
- `emit(event, payload): void` — internal; called by `SpritePlayer`.
- `clear(): void` — drops every listener.
### Event payloads
- `play` → `{ handleId, entryName, startedAt }`
- `stop` → `{ handleId, entryName, fadeOutMs }`
- `complete` → `{ handleId, entryName, durationMs }`
- `voice-stolen` → `{ stolenId, replacedBy, entryName }`
- `error` → `{ handleId, entryName, code, message }`
## Implementation Notes
- The class deliberately exposes `emit` so the orchestrator can fire events; downstream consumers should treat it as internal and never call it (TypeScript visibility cannot enforce package-level boundaries, so the convention is documented here).
- `clear()` is invoked by `SpritePlayer.dispose()` to release references — consumers should not call it directly because it would silence other listeners.
- The underlying `EventBus` dispatches synchronously in FIFO order; throwing in a listener does not poison the bus but does prevent later listeners from running for that emission.