using Microsoft.JSInterop;
namespace DeepDrftPublic.Client.Services;
///
/// Thin C# wrapper over the window.DeepDrftBeacon TS interop (Phase 16 §2.2). Wraps the
/// navigator.sendBeacon POST and the page-unload registration so the rest of the client never
/// touches string identifiers directly. All calls are best-effort: a JS
/// failure (module not yet loaded, interop unavailable during prerender) is swallowed — telemetry must
/// never throw into the UI or the playback path.
///
public sealed class BeaconInterop
{
private readonly IJSRuntime _js;
public BeaconInterop(IJSRuntime js)
{
_js = js;
}
/// Queue a fire-and-forget POST of a JSON body to the given absolute URL.
public async Task SendAsync(string url, string json)
{
try
{
await _js.InvokeAsync("DeepDrftBeacon.send", url, json);
}
catch
{
// Module not loaded / not interactive yet — drop the event silently.
}
}
/// Register a .NET unload callback (fires on pagehide / visibility→hidden) under a key.
public async Task RegisterUnloadAsync(string key, DotNetObjectReference dotNetRef, string methodName)
where T : class
{
try
{
await _js.InvokeVoidAsync("DeepDrftBeacon.registerUnload", key, dotNetRef, methodName);
}
catch
{
// Best-effort — without the unload handler, mid-play tab-close simply isn't recorded.
}
}
/// Detach a previously-registered unload callback.
public async Task UnregisterUnloadAsync(string key)
{
try
{
await _js.InvokeVoidAsync("DeepDrftBeacon.unregisterUnload", key);
}
catch
{
// Disposal best-effort.
}
}
}