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. } } }