2af0d8650b
Route normal play closes (end/switch/stop) and all shares through a same-origin HttpClient POST so privacy-hardened browsers stop blocking them; keep sendBeacon for the tab-unload edge. Rename the JS module off telemetry/beacon to session/ lifecycle so the retained fallback isn't name-matched. No new data or identifiers.
35 lines
1.8 KiB
C#
35 lines
1.8 KiB
C#
using DeepDrftModels.Enums;
|
|
|
|
namespace DeepDrftPublic.Client.Services;
|
|
|
|
/// <summary>
|
|
/// The emit seam for the <see cref="PlayTracker"/> (Phase 16 §2.1). The tracker owns the session
|
|
/// lifecycle, the engagement floor, and the bucket classification but knows nothing about transport —
|
|
/// it hands a finished classification to a sink, choosing only which arm fits the close that triggered
|
|
/// it. Two arms exist because the close paths differ in whether the page survives the call (telemetry
|
|
/// transport-resilience):
|
|
/// <list type="bullet">
|
|
/// <item><see cref="EmitPlayAsync"/> — normal closes (organic end / track-switch / stop), where the page
|
|
/// stays alive, go over a first-party <c>HttpClient</c> POST to <c>api/event/play</c>. A first-party
|
|
/// fetch is not name-matched by tracking/fingerprinting heuristics the way a <c>sendBeacon</c> module is.</item>
|
|
/// <item><see cref="EmitPlayOnUnload"/> — the page-unload edge (pagehide / visibility→hidden), where an
|
|
/// awaited fetch would be cancelled, still goes over <c>navigator.sendBeacon</c>.</item>
|
|
/// </list>
|
|
/// Tests substitute a fake sink to assert floor and bucket behaviour with no transport.
|
|
/// </summary>
|
|
public interface IPlayEventSink
|
|
{
|
|
/// <summary>
|
|
/// Emit one recorded play over the first-party fetch transport (normal close: end / switch / stop).
|
|
/// Called at most once per session, only when the floor is crossed. Awaitable but safe to
|
|
/// fire-and-forget on a live page; never throws.
|
|
/// </summary>
|
|
Task EmitPlayAsync(string trackEntryKey, PlayBucket bucket);
|
|
|
|
/// <summary>
|
|
/// Emit one recorded play over <c>sendBeacon</c> for the page-unload edge, where an awaited fetch
|
|
/// would be cancelled as the page freezes. Synchronous and fire-and-forget; never throws.
|
|
/// </summary>
|
|
void EmitPlayOnUnload(string trackEntryKey, PlayBucket bucket);
|
|
}
|