V13-FE-011: finalize search list layout slice
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
using System.Text.Json;
|
||||
using Kbx.Shared.Telemetry.Generated;
|
||||
using Kbx.Shared.Experiments.Generated;
|
||||
|
||||
namespace Kbx.Shared.Telemetry;
|
||||
|
||||
public sealed record KbxUxEventRequest(
|
||||
string EventName,
|
||||
string? ScreenId,
|
||||
string? ScreenVersion,
|
||||
Guid SessionId,
|
||||
Guid? TaskSessionId,
|
||||
string? AppVersion,
|
||||
string? ExperimentId,
|
||||
string? ExperimentVariant,
|
||||
DateTimeOffset OccurredAt,
|
||||
int? DurationMs,
|
||||
int? Count,
|
||||
IReadOnlyDictionary<string,string>? Attributes);
|
||||
|
||||
public sealed record KbxUxEventBatchRequest(IReadOnlyList<KbxUxEventRequest> Events);
|
||||
public sealed record KbxUxMetricRow(string MetricKey,string Label,double? Value,string Unit,long SampleCount,double? P50=null,double? P95=null);
|
||||
public sealed record KbxUxMetricsResponse(DateOnly From,DateOnly To,string? ScreenId,IReadOnlyList<KbxUxMetricRow> Metrics);
|
||||
|
||||
public static class KbxUxTelemetryGuard
|
||||
{
|
||||
private static readonly string[] ForbiddenFragments = ["phone","address","name","orderno","customer","itemcode","barcode","keyword","query","email","businessnumber","entityid"];
|
||||
public static void Validate(KbxUxEventRequest item)
|
||||
{
|
||||
if (!KbxTelemetryCatalog.Events.TryGetValue(item.EventName,out var definition)) throw new ArgumentException($"Unknown telemetry event: {item.EventName}");
|
||||
if (definition.RequiresDuration && item.DurationMs is null) throw new ArgumentException($"{item.EventName} requires durationMs.");
|
||||
if (item.DurationMs is < 0 or > 86_400_000) throw new ArgumentOutOfRangeException(nameof(item.DurationMs));
|
||||
if (item.ExperimentId is { Length: > 160 } || item.ExperimentVariant is { Length: > 80 }) throw new ArgumentException("Experiment context is too long.");
|
||||
if ((item.ExperimentId is null) != (item.ExperimentVariant is null)) throw new ArgumentException("Experiment id and variant must be supplied together.");
|
||||
if (item.Count is < 1 or > 1_000_000) throw new ArgumentOutOfRangeException(nameof(item.Count));
|
||||
var allowed=definition.AllowedAttributes.ToHashSet(StringComparer.Ordinal);
|
||||
foreach(var pair in item.Attributes ?? new Dictionary<string,string>())
|
||||
{
|
||||
if(!allowed.Contains(pair.Key)) throw new ArgumentException($"Attribute '{pair.Key}' is not allowed for {item.EventName}.");
|
||||
if(ForbiddenFragments.Any(x=>pair.Key.Contains(x,StringComparison.OrdinalIgnoreCase))) throw new ArgumentException($"Attribute '{pair.Key}' is forbidden for telemetry.");
|
||||
if(pair.Value.Length>80) throw new ArgumentException($"Attribute value is too long: {pair.Key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user