using Microsoft.JSInterop;
namespace DnsmasqWebUI.Extensions;
///
/// Safe JS interop helpers that swallow disconnect/cancel/dispose exceptions.
/// Use for best-effort or teardown calls; use raw InvokeVoidAsync/InvokeAsync when failure must propagate.
///
public static class JSRuntimeExtensions
{
///
/// Invokes a void JS function without throwing on circuit disconnect, cancel, or dispose.
/// Returns true if the call succeeded, false otherwise.
///
public static async ValueTask InvokeVoidAsyncSafe(
this IJSRuntime js,
string identifier,
CancellationToken cancellationToken = default,
params object?[]? args)
{
try
{
var a = args ?? [];
if (cancellationToken == default)
await js.InvokeVoidAsync(identifier, a);
else
await js.InvokeVoidAsync(identifier, cancellationToken, a);
return true;
}
catch (JSDisconnectedException) { return false; }
catch (TaskCanceledException) { return false; }
catch (ObjectDisposedException) { return false; }
}
///
/// Invokes a JS function that returns a value, without throwing on circuit disconnect, cancel, or dispose.
/// Returns default when the call fails (e.g. circuit gone).
///
public static async ValueTask InvokeAsyncSafe(
this IJSRuntime js,
string identifier,
CancellationToken cancellationToken = default,
params object?[]? args)
{
try
{
var a = args ?? [];
if (cancellationToken == default)
return await js.InvokeAsync(identifier, a);
return await js.InvokeAsync(identifier, cancellationToken, a);
}
catch (JSDisconnectedException) { return default; }
catch (TaskCanceledException) { return default; }
catch (ObjectDisposedException) { return default; }
}
}