fix(web): ignore malformed dashboard tile snapshots

This commit is contained in:
vince 2026-06-20 14:32:09 +02:00
parent 4ce42fb52b
commit 88c448258d
3 changed files with 112 additions and 1 deletions

View file

@ -231,7 +231,12 @@ export function createDashboardTileSnapshotStore(
return null;
}
return payload as DashboardTileSnapshotPayload;
return {
currentRevisionId: payload.currentRevisionId,
schemaVersion: payload.schemaVersion,
tiles: payload.tiles.filter(isDashboardTileSnapshotRecord),
version: 1,
};
} catch {
return null;
}
@ -332,6 +337,51 @@ function dashboardTileSnapshotKey(tile: DashboardTileReference): string {
return JSON.stringify(tile);
}
function isDashboardTileSnapshotRecord(
value: unknown,
): value is DashboardTileSnapshotRecord {
if (!isSnapshotRecord(value)) return false;
return (
typeof value.savedAt === "number" &&
Number.isFinite(value.savedAt) &&
isDashboardTileReference(value.tile) &&
isDashboardTileSnapshotItem(value.item)
);
}
function isDashboardTileReference(
value: unknown,
): value is DashboardTileReference {
if (!isSnapshotRecord(value) || typeof value.kind !== "string") return false;
switch (value.kind) {
case "telemetry":
case "module":
return typeof value.id === "string";
case "service":
return typeof value.groupId === "string" && typeof value.id === "string";
case "status":
return typeof value.stripId === "string" && typeof value.id === "string";
default:
return false;
}
}
function isDashboardTileSnapshotItem(
value: unknown,
): value is DashboardTileSnapshotItem {
return (
isSnapshotRecord(value) &&
typeof value.id === "string" &&
(value.detail === undefined || typeof value.detail === "string")
);
}
function isSnapshotRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}
function staleDashboardTileDetail(
detail: string | undefined,
ageMs: number,