

































@@ -0,0 +1,123 @@
1+import type { CaptureSavedView } from "./ui-render.js";
2+3+const MAX_SAVED_VIEWS = 12;
4+const MAX_FILTER_ITEMS = 64;
5+const MAX_FILTER_VALUE_LENGTH = 256;
6+const MAX_NAME_LENGTH = 80;
7+const MAX_SEARCH_TEXT_LENGTH = 500;
8+9+const headerModes = new Set<CaptureSavedView["headerMode"]>(["key", "all", "hidden"]);
10+const viewModes = new Set<CaptureSavedView["viewMode"]>(["list", "timeline"]);
11+const groupModes = new Set<CaptureSavedView["groupMode"]>(["none", "flow", "host-path", "burst"]);
12+const timelineLaneModes = new Set<CaptureSavedView["timelineLaneMode"]>([
13+"domain",
14+"provider",
15+"flow",
16+]);
17+const timelineLaneSorts = new Set<CaptureSavedView["timelineLaneSort"]>([
18+"most-events",
19+"most-errors",
20+"severity",
21+"alphabetical",
22+]);
23+const timelineZooms = new Set<CaptureSavedView["timelineZoom"]>([75, 100, 150, 200, 300]);
24+const timelineSparklineModes = new Set<CaptureSavedView["timelineSparklineMode"]>([
25+"session-relative",
26+"lane-relative",
27+]);
28+const detailPlacements = new Set<CaptureSavedView["detailPlacement"]>(["right", "bottom"]);
29+const payloadLayouts = new Set<NonNullable<CaptureSavedView["payloadLayout"]>>([
30+"formatted",
31+"raw",
32+]);
33+const payloadExtents = new Set<CaptureSavedView["payloadExtent"]>(["preview", "full"]);
34+35+function readString(value: unknown, maxLength: number): string | null {
36+if (typeof value !== "string") {
37+return null;
38+}
39+const trimmed = value.trim();
40+return trimmed ? trimmed.slice(0, maxLength) : null;
41+}
42+43+function readStringArray(value: unknown): string[] {
44+if (!Array.isArray(value)) {
45+return [];
46+}
47+return value
48+.filter((item): item is string => typeof item === "string")
49+.map((item) => item.trim().slice(0, MAX_FILTER_VALUE_LENGTH))
50+.filter(Boolean)
51+.slice(0, MAX_FILTER_ITEMS);
52+}
53+54+function readEnum<T extends string>(value: unknown, allowed: Set<T>, fallback: T): T {
55+return typeof value === "string" && allowed.has(value as T) ? (value as T) : fallback;
56+}
57+58+function readNullableEnum<T extends string>(value: unknown, allowed: Set<T>): T | null {
59+return typeof value === "string" && allowed.has(value as T) ? (value as T) : null;
60+}
61+62+function readTimelineZoom(value: unknown): CaptureSavedView["timelineZoom"] {
63+return typeof value === "number" && timelineZooms.has(value as CaptureSavedView["timelineZoom"])
64+ ? (value as CaptureSavedView["timelineZoom"])
65+ : 100;
66+}
67+68+export function normalizeCaptureSavedView(value: unknown): CaptureSavedView | null {
69+const record =
70+typeof value === "object" && value !== null ? (value as Record<string, unknown>) : null;
71+if (!record) {
72+return null;
73+}
74+const id = readString(record.id, MAX_FILTER_VALUE_LENGTH);
75+const name = readString(record.name, MAX_NAME_LENGTH);
76+if (!id || !name) {
77+return null;
78+}
79+return {
80+ id,
81+ name,
82+sessionIds: readStringArray(record.sessionIds),
83+kindFilter: readStringArray(record.kindFilter),
84+providerFilter: readStringArray(record.providerFilter),
85+hostFilter: readStringArray(record.hostFilter),
86+searchText:
87+typeof record.searchText === "string"
88+ ? record.searchText.slice(0, MAX_SEARCH_TEXT_LENGTH)
89+ : "",
90+headerMode: readEnum(record.headerMode, headerModes, "key"),
91+viewMode: readEnum(record.viewMode, viewModes, "list"),
92+groupMode: readEnum(record.groupMode, groupModes, "none"),
93+timelineLaneMode: readEnum(record.timelineLaneMode, timelineLaneModes, "domain"),
94+timelineLaneSort: readEnum(record.timelineLaneSort, timelineLaneSorts, "most-events"),
95+timelineZoom: readTimelineZoom(record.timelineZoom),
96+timelineSparklineMode: readEnum(
97+record.timelineSparklineMode,
98+timelineSparklineModes,
99+"session-relative",
100+),
101+errorsOnly: record.errorsOnly === true,
102+detailPlacement: readEnum(record.detailPlacement, detailPlacements, "right"),
103+payloadLayout: readNullableEnum(record.payloadLayout, payloadLayouts),
104+payloadExtent: readEnum(record.payloadExtent, payloadExtents, "preview"),
105+};
106+}
107+108+export function normalizeCaptureSavedViews(value: unknown): CaptureSavedView[] {
109+if (!Array.isArray(value)) {
110+return [];
111+}
112+const views: CaptureSavedView[] = [];
113+for (const item of value) {
114+const view = normalizeCaptureSavedView(item);
115+if (view) {
116+views.push(view);
117+}
118+if (views.length >= MAX_SAVED_VIEWS) {
119+break;
120+}
121+}
122+return views;
123+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。