feat(web): events dispatcher posts to /api/events on player transitions

useEventsDispatcher subscribes to player.current/state via \$effect:
on first transition to playing for a new track, POSTs play_started
and caches the id; on track-id change while a play is open, closes
the prior row as play_skipped; on natural completion (state
playing→paused with position >= duration > 0), POSTs play_ended;
on pagehide, navigator.sendBeacon fires a final play_skipped.
Stable per-tab client_id from sessionStorage.
This commit is contained in:
2026-04-26 09:42:11 -04:00
parent 599a19f780
commit b6f8a0c390
5 changed files with 289 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
const KEY = 'minstrel.client_id';
export function getOrCreateClientId(): string {
try {
const existing = sessionStorage.getItem(KEY);
if (existing) return existing;
} catch {
// sessionStorage unavailable (non-browser env). Generate ephemerally.
}
const id = crypto.randomUUID();
try { sessionStorage.setItem(KEY, id); } catch { /* ignore */ }
return id;
}