Event-Queue und TypeScript-API
FIFO-Semantik
Das Rust-Backend verwaltet genau eine globale, unbeschränkte In-Memory-Queue.
- Jedes
AppEventwird hinten eingereiht. - Für den Kopf wird eine Momentaufnahme aller aktuell passenden Listener (
typeoder*) gebildet. - Ohne Listener wird der Event als
skippedabgeschlossen. - Für jeden Listener entsteht eine Delivery mit eigener ID und Deadline.
- Der nächste Event beginnt erst, wenn alle Deliveries bestätigt oder automatisch freigegeben sind.
Automatische Freigabe erfolgt bei Listenerfehler, Timeout, Unsubscribe oder Browser-Disconnect. Disconnect gilt sofort als Bestätigung, damit ein OBS-Szenenwechsel nicht blockiert.
Timeouts beginnen bei der Auslieferung. Default sind 10 Sekunden; erlaubt sind 100 ms bis 300 Sekunden. delivery.signal wird zur Deadline abgebrochen.
Die Queue überlebt Browser-Reloads und Szenenwechsel, wird aber bei einem vollständigen Streamertool-Neustart geleert.
TypeScript-API
export interface StreamertoolEvent<T = unknown> {
id: string;
source: string;
type: string;
payload: T;
createdAt: string;
}
export interface EventDelivery {
readonly id: string;
readonly listenerId: string;
readonly deadline: string;
readonly signal: AbortSignal;
ack(): void;
}
export interface ListenerOptions { timeoutMs?: number }
export type EventHandler<T = unknown> = (
event: StreamertoolEvent<T>,
delivery: EventDelivery,
) => void | Promise<void>;
export interface StreamertoolEvents {
on<T = unknown>(
type: string | "*",
handler: EventHandler<T>,
options?: ListenerOptions,
): () => void;
}
delivery.ack() ist idempotent und bestätigt nur diesen Listener. Die Rückgabe oder Auflösung eines Promise bestätigt ausdrücklich nicht automatisch. Fehler geben die betroffene Delivery dagegen sofort frei.
Seriell anzeigen
const off = Streamertool.events.on("twitch.follow", (event, delivery) => {
show(event.payload);
setTimeout(() => {
hide();
delivery.ack();
}, 5000);
}, { timeoutMs: 10000 });
Kontrolliert überlappen
Streamertool.events.on("twitch.chat.message", (event, delivery) => {
appendMessage(event.payload);
delivery.ack(); // nächster Event darf sofort starten
animateMessageIn(); // Animation läuft trotzdem weiter
});
WebSocket-Frames
Client: register, unregister, ack, listenerError.
Server: ready, delivery und control. Alle Feldnamen sind camelCase. Registrierungen enthalten stabile Listener-ID, Event-Typ und Timeout; eine Delivery enthält Delivery-ID, Listener-ID, Deadline und den vollständigen Originalevent.