import type { DashboardDocument, DashboardModule, MetricValue, ServiceEntry, ServiceGroup, Severity, StatusItem, StatusStrip, TelemetryCard, } from "@dimensionlab/dashboard-model"; export type DashboardTileReference = | { kind: "telemetry"; id: string } | { kind: "service"; groupId: string; id: string } | { kind: "module"; id: string } | { kind: "status"; stripId: string; id: string }; export type DashboardTileItem = | DashboardModule | ServiceEntry | StatusItem | TelemetryCard; export type DashboardTileResolution = | { state: "ready"; tile: DashboardTileReference; item: DashboardTileItem; } | { state: "not_found"; tile: DashboardTileReference; message: string; } | { state: "disabled"; tile: DashboardTileReference; message: string; }; export interface DatasourceResolutionOptions { fetch?: DatasourceFetch; prometheusBaseUrl?: string; prometheusRangeSeconds?: number; prometheusStepSeconds?: number; requestTimeoutMs?: number; } export async function resolveDashboardDatasources( document: DashboardDocument, options: DatasourceResolutionOptions = {}, ): Promise { const context = datasourceContext(options); const telemetry = await Promise.all( document.telemetry.map((card) => resolveTelemetryCard(card, context)), ); const serviceGroups = await Promise.all( document.serviceGroups.map((group) => resolveServiceGroup(group, context)), ); const modules = await resolveModules(document.modules || [], serviceGroups, context); const statusStrips = await resolveStatusStrips( document.statusStrips, document.metadata.refreshIntervalSeconds, serviceGroups, context, ); return { ...structuredClone(document), telemetry, serviceGroups, modules, statusStrips, }; } export async function resolveDashboardTile( document: DashboardDocument, tile: DashboardTileReference, options: DatasourceResolutionOptions = {}, ): Promise { const context = datasourceContext(options); if (tile.kind === "telemetry") { const card = document.telemetry.find((item) => item.id === tile.id); if (!card) return missingTile(tile); return { state: "ready", tile, item: await resolveTelemetryCard(card, context), }; } if (tile.kind === "service") { const service = document.serviceGroups .find((group) => group.id === tile.groupId) ?.services.find((item) => item.id === tile.id); if (!service) return missingTile(tile); return { state: "ready", tile, item: await resolveService(service, context), }; } if (tile.kind === "module") { const module = document.modules?.find((item) => item.id === tile.id); if (!module) return missingTile(tile); const item = module.id === "runtime-health-summary" ? runtimeHealthSummary( module, await Promise.all( document.serviceGroups.map((group) => resolveServiceGroup(group, context)), ), ) : await resolveModule(module, context); return { state: "ready", tile, item }; } const strip = document.statusStrips.find((item) => item.id === tile.stripId); const statusItem = strip?.items.find((item) => item.id === tile.id); if (!strip || !statusItem) return missingTile(tile); return { state: "ready", tile, item: await resolveStatusTile( statusItem, document.metadata.refreshIntervalSeconds, document.serviceGroups, context, ), }; } interface DatasourceContext { fetch: DatasourceFetch; prometheusBaseUrl: string; prometheusRangeSeconds: number; prometheusStepSeconds: number; requestTimeoutMs: number; } type DatasourceFetch = (input: string, init?: RequestInit) => Promise; interface PrometheusVectorResult { metric?: Record; value?: [number, string]; } interface PrometheusMatrixResult { metric?: Record; values?: Array<[number, string]>; } function datasourceContext(options: DatasourceResolutionOptions): DatasourceContext { return { fetch: options.fetch || globalThis.fetch, prometheusBaseUrl: options.prometheusBaseUrl || process.env.PROMETHEUS_BASE_URL || "https://prometheus.dimensionlab.net", prometheusRangeSeconds: options.prometheusRangeSeconds || 60 * 60, prometheusStepSeconds: options.prometheusStepSeconds || 120, requestTimeoutMs: options.requestTimeoutMs || 2_500, }; } async function resolveTelemetryCard( card: TelemetryCard, context: DatasourceContext, ): Promise { if (card.datasource?.type !== "external" || card.datasource.adapter !== "prometheus") { return structuredClone(card); } try { const [instant, range] = await Promise.all([ prometheusQuery(card.datasource.reference, context), prometheusRangeQuery(card.datasource.reference, context), ]); const current = pickMaxVectorResult(instant); const currentValue = Number(current?.value?.[1]); const sparkline = matrixPoints(range); if (!Number.isFinite(currentValue)) return markStale(card, "no telemetry data"); return { ...structuredClone(card), value: metricValueWithLiveNumber(card.value, currentValue), severity: severityForValue(currentValue, card.thresholds), detail: prometheusMetricDetail(current?.metric || {}, card.detail), sparkline: sparkline.length ? sparkline : card.sparkline, }; } catch { return markStale(card, card.detail || "telemetry unavailable"); } } async function resolveServiceGroup( group: ServiceGroup, context: DatasourceContext, ): Promise { return { ...structuredClone(group), services: await Promise.all( group.services.map((service) => resolveService(service, context)), ), }; } async function resolveService( service: ServiceEntry, context: DatasourceContext, ): Promise { const datasource = service.datasource; if (datasource?.type !== "external") return structuredClone(service); if (datasource.adapter === "http-status") { return resolveHttpStatusService(service, datasource.reference, context); } if (datasource.adapter === "prometheus") { return resolvePrometheusService(service, datasource.reference, context); } return structuredClone(service); } async function resolveHttpStatusService( service: ServiceEntry, reference: string, context: DatasourceContext, ): Promise { const request = parseHttpStatusReference(reference); if (!request) return structuredClone(service); try { const startedAt = Date.now(); const response = await fetchWithTimeout( context.fetch, request.url, { cache: "no-store", method: request.method, }, context.requestTimeoutMs, ); const elapsedMs = Math.max(0, Math.round(Date.now() - startedAt)); const badge = await uptimeBadge(response); if (badge) { const ping = badge.ping; const status = badge.status || "UNKNOWN"; return { ...structuredClone(service), severity: uptimeBadgeSeverity(status), detail: Number.isFinite(ping) ? `${Math.round(ping as number)} ms` : status.toLowerCase(), }; } return { ...structuredClone(service), severity: response.ok ? "ok" : response.status >= 500 ? "danger" : "warning", detail: response.ok ? `${elapsedMs} ms` : `HTTP ${response.status}`, }; } catch { return { ...structuredClone(service), severity: "unavailable", detail: "unavailable", }; } } async function resolvePrometheusService( service: ServiceEntry, reference: string, context: DatasourceContext, ): Promise { try { const result = pickMaxVectorResult(await prometheusQuery(reference, context)); const value = Number(result?.value?.[1]); const ok = Number.isFinite(value) && value > 0; return { ...structuredClone(service), severity: ok ? "ok" : "unavailable", detail: ok ? "up" : "down", }; } catch { return { ...structuredClone(service), severity: "unavailable", detail: "unavailable", }; } } async function resolveModules( modules: DashboardModule[], serviceGroups: ServiceGroup[], context: DatasourceContext, ): Promise { const resolved = await Promise.all( modules.map((module) => resolveModule(module, context)), ); return resolved.map((module) => module.id === "runtime-health-summary" ? runtimeHealthSummary(module, serviceGroups) : module, ); } async function resolveModule( module: DashboardModule, context: DatasourceContext, ): Promise { if (module.datasource?.type !== "external" || module.datasource.adapter !== "weather") { return structuredClone(module); } try { const weather = await requestJson( context.fetch, openMeteoUrl(module.datasource.reference), context.requestTimeoutMs, ); const current = weather.current; const temperature = Number(current?.temperature_2m); if (!Number.isFinite(temperature)) { return { ...structuredClone(module), severity: "stale", detail: "weather unavailable", }; } const apparent = Number(current?.apparent_temperature); const wind = Number(current?.wind_speed_10m); const condition = weatherCondition(Number(current?.weather_code)); return { ...structuredClone(module), value: `${temperature.toFixed(1)} C`, detail: [ condition, Number.isFinite(apparent) ? `feels ${apparent.toFixed(1)} C` : "", Number.isFinite(wind) ? `wind ${Math.round(wind)} km/h` : "", ].filter(Boolean).join(" - "), severity: "ok", }; } catch { return { ...structuredClone(module), severity: "stale", detail: "weather unavailable", }; } } function runtimeHealthSummary( module: DashboardModule, serviceGroups: ServiceGroup[], ): DashboardModule { const services = serviceGroups.flatMap((group) => group.services); const down = services.filter((service) => service.severity === "danger" || service.severity === "unavailable" ).length; const warning = services.filter((service) => service.severity === "warning").length; const ok = services.filter((service) => service.severity === "ok").length; if (down > 0) { return { ...structuredClone(module), value: `${down} service${down === 1 ? "" : "s"} down`, detail: `${warning} warning${warning === 1 ? "" : "s"} - ${ok} service${ok === 1 ? "" : "s"} ok`, severity: "danger", }; } if (warning > 0) { return { ...structuredClone(module), value: `${warning} service${warning === 1 ? "" : "s"} warning`, detail: `${ok} service${ok === 1 ? "" : "s"} ok`, severity: "warning", }; } return { ...structuredClone(module), value: "all systems operational", detail: `${ok} service${ok === 1 ? "" : "s"} ok`, severity: "ok", }; } async function resolveStatusStrips( strips: StatusStrip[], refreshIntervalSeconds: number | undefined, serviceGroups: ServiceGroup[], context: DatasourceContext, ): Promise { const [uptime, loadAverage] = await Promise.all([ prometheusScalar( 'time() - node_boot_time_seconds{job="node",host="linux-infra"}', context, ).catch(() => null), prometheusLoadAverage(context).catch(() => null), ]); const health = serviceHealthSummary(serviceGroups); return strips.map((strip) => ({ ...structuredClone(strip), items: strip.items.map((item) => resolveStatusItem(item, { health, loadAverage, refreshIntervalSeconds, uptime, }), ), })); } function resolveStatusItem( item: StatusItem, values: { health: { severity: Severity; value: string }; loadAverage: string | null; refreshIntervalSeconds?: number; uptime: number | null; }, ): StatusItem { if (item.id === "system-status") { return { ...structuredClone(item), value: values.health.value, severity: values.health.severity, }; } if (item.id === "last-sync") { return { ...structuredClone(item), value: "just now", severity: "ok", }; } if (item.id === "uptime" && values.uptime !== null) { return { ...structuredClone(item), value: formatDuration(values.uptime), severity: "ok", }; } if (item.id === "load-avg" && values.loadAverage) { return { ...structuredClone(item), value: values.loadAverage, severity: "neutral", }; } if (item.id === "auto-refresh" && values.refreshIntervalSeconds) { return { ...structuredClone(item), value: `${values.refreshIntervalSeconds}s`, severity: "neutral", }; } return structuredClone(item); } async function resolveStatusTile( item: StatusItem, refreshIntervalSeconds: number | undefined, serviceGroups: ServiceGroup[], context: DatasourceContext, ): Promise { if (item.id === "system-status") { const resolvedGroups = await Promise.all( serviceGroups.map((group) => resolveServiceGroup(group, context)), ); const health = serviceHealthSummary(resolvedGroups); return { ...structuredClone(item), value: health.value, severity: health.severity, }; } if (item.id === "last-sync") { return { ...structuredClone(item), value: "just now", severity: "ok", }; } if (item.id === "uptime") { const uptime = await prometheusScalar( 'time() - node_boot_time_seconds{job="node",host="linux-infra"}', context, ).catch(() => null); return uptime === null ? structuredClone(item) : { ...structuredClone(item), value: formatDuration(uptime), severity: "ok", }; } if (item.id === "load-avg") { const loadAverage = await prometheusLoadAverage(context).catch(() => null); return loadAverage ? { ...structuredClone(item), value: loadAverage, severity: "neutral", } : structuredClone(item); } if (item.id === "auto-refresh" && refreshIntervalSeconds) { return { ...structuredClone(item), value: `${refreshIntervalSeconds}s`, severity: "neutral", }; } return structuredClone(item); } function serviceHealthSummary(serviceGroups: ServiceGroup[]): { severity: Severity; value: string; } { const services = serviceGroups.flatMap((group) => group.services); const down = services.filter((service) => service.severity === "danger" || service.severity === "unavailable" ).length; const warning = services.filter((service) => service.severity === "warning").length; if (down > 0) { return { severity: "danger", value: `${down} service${down === 1 ? "" : "s"} down`, }; } if (warning > 0) { return { severity: "warning", value: `${warning} service${warning === 1 ? "" : "s"} warning`, }; } return { severity: "ok", value: "All systems operational", }; } async function prometheusQuery( query: string, context: DatasourceContext, ): Promise { const url = prometheusApiUrl(context.prometheusBaseUrl, "/api/v1/query", { query, }); const payload = await requestJson>( context.fetch, url, context.requestTimeoutMs, ); return payload.status === "success" ? payload.data.result || [] : []; } async function prometheusRangeQuery( query: string, context: DatasourceContext, ): Promise { const end = Math.floor(Date.now() / 1000); const start = end - context.prometheusRangeSeconds; const url = prometheusApiUrl(context.prometheusBaseUrl, "/api/v1/query_range", { query, start: String(start), end: String(end), step: String(context.prometheusStepSeconds), }); const payload = await requestJson>( context.fetch, url, context.requestTimeoutMs, ); return payload.status === "success" ? payload.data.result || [] : []; } async function prometheusScalar( query: string, context: DatasourceContext, ): Promise { const result = pickMaxVectorResult(await prometheusQuery(query, context)); const value = Number(result?.value?.[1]); return Number.isFinite(value) ? value : null; } async function prometheusLoadAverage(context: DatasourceContext): Promise { const [one, five, fifteen] = await Promise.all([ prometheusScalar('node_load1{job="node",host="linux-infra"}', context), prometheusScalar('node_load5{job="node",host="linux-infra"}', context), prometheusScalar('node_load15{job="node",host="linux-infra"}', context), ]); if (one === null || five === null || fifteen === null) return null; return [one, five, fifteen].map((value) => value.toFixed(2)).join(" "); } async function requestJson( fetch: DatasourceFetch, url: string, timeoutMs: number, ): Promise { const response = await fetchWithTimeout( fetch, url, { cache: "no-store" }, timeoutMs, ); if (!response.ok) throw new Error(`request failed: ${response.status}`); return response.json() as Promise; } async function fetchWithTimeout( fetch: DatasourceFetch, url: string, init: RequestInit, timeoutMs: number, ): Promise { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); try { return await fetch(url, { ...init, signal: controller.signal, }); } finally { clearTimeout(timeout); } } function prometheusApiUrl( baseUrl: string, pathname: string, params: Record, ): string { const url = new URL(pathname, ensureTrailingSlash(baseUrl)); Object.entries(params).forEach(([key, value]) => url.searchParams.set(key, value)); return url.toString(); } function ensureTrailingSlash(value: string): string { return value.endsWith("/") ? value : `${value}/`; } function pickMaxVectorResult( results: PrometheusVectorResult[], ): PrometheusVectorResult | null { return results.reduce((winner, item) => { if (!winner) return item; return Number(item.value?.[1]) > Number(winner.value?.[1]) ? item : winner; }, null); } function matrixPoints(results: PrometheusMatrixResult[]): number[] { const byTimestamp = new Map(); for (const series of results) { for (const [timestamp, value] of series.values || []) { const numeric = Number(value); if (!Number.isFinite(numeric)) continue; const previous = byTimestamp.get(timestamp); if (previous === undefined || numeric > previous) { byTimestamp.set(timestamp, numeric); } } } return [...byTimestamp.entries()] .sort(([left], [right]) => left - right) .map(([, value]) => value); } function metricValueWithLiveNumber(value: MetricValue, nextValue: number): MetricValue { if (value.kind === "text") return value; return { ...value, value: value.kind === "percent" ? clamp(nextValue, 0, 100) : Math.max(0, nextValue), }; } function severityForValue( value: number, thresholds: TelemetryCard["thresholds"], ): Severity { if (thresholds?.danger !== undefined && value >= thresholds.danger) return "danger"; if (thresholds?.warning !== undefined && value >= thresholds.warning) return "warning"; return "ok"; } function prometheusMetricDetail( metric: Record, fallback = "", ): string { const host = metric.host || metric.instance || metric.job; const detail = metric.mountpoint || metric.name || metric.container || metric.id; const parts = [host, detail].filter(Boolean); if (parts.length) return parts.join(" "); return fallback.replace(/^fallback\s*-\s*/i, "") || "telemetry"; } function markStale(card: TelemetryCard, detail: string): TelemetryCard { return { ...structuredClone(card), severity: "stale", detail, }; } function parseHttpStatusReference(reference: string): { method: string; url: string } | null { const match = /^(GET|HEAD|POST)\s+(.+)$/i.exec(reference.trim()); if (!match) return null; return { method: match[1].toUpperCase(), url: match[2] }; } interface PrometheusResponse { status: string; data: { result?: T[]; }; } interface OpenMeteoResponse { current?: { apparent_temperature?: number; temperature_2m?: number; weather_code?: number; wind_speed_10m?: number; }; } interface UptimeBadgeResponse { status?: string; ping?: number; } async function uptimeBadge(response: Response): Promise { const contentType = response.headers.get("content-type") || ""; if (!contentType.includes("json")) return null; try { const payload = await response.clone().json() as UptimeBadgeResponse; return typeof payload.status === "string" ? payload : null; } catch { return null; } } function uptimeBadgeSeverity(status = ""): Severity { const normalized = status.toUpperCase(); if (normalized === "UP") return "ok"; if (normalized === "PENDING" || normalized === "MAINTENANCE") return "warning"; return "unavailable"; } function openMeteoUrl(reference: string): string { const params = new URLSearchParams(); const serialized = reference.startsWith("open-meteo:") ? reference.slice("open-meteo:".length) : reference; new URLSearchParams(serialized).forEach((value, key) => { params.set(key, value); }); params.set( "current", "temperature_2m,apparent_temperature,weather_code,wind_speed_10m", ); params.set("timezone", "Europe/Amsterdam"); return `https://api.open-meteo.com/v1/forecast?${params.toString()}`; } function weatherCondition(code: number): string { if (code === 0) return "Clear"; if ([1, 2].includes(code)) return "Partly cloudy"; if (code === 3) return "Cloudy"; if ([45, 48].includes(code)) return "Fog"; if (code >= 51 && code <= 67) return "Rain"; if (code >= 71 && code <= 77) return "Snow"; if (code >= 80 && code <= 82) return "Showers"; if (code >= 95) return "Thunderstorm"; return "Mixed"; } function clamp(value: number, min: number, max: number): number { return Math.max(min, Math.min(max, value)); } function formatDuration(totalSeconds: number): string { const seconds = Math.max(0, Math.floor(totalSeconds)); const days = Math.floor(seconds / 86_400); const hours = Math.floor((seconds % 86_400) / 3_600); const minutes = Math.floor((seconds % 3_600) / 60); return `${days}d ${hours}h ${minutes}m`; } function missingTile(tile: DashboardTileReference): DashboardTileResolution { return { state: "not_found", tile, message: `Dashboard tile not found: ${tileKey(tile)}`, }; } function tileKey(tile: DashboardTileReference): string { if (tile.kind === "status") return `${tile.kind}:${tile.stripId}:${tile.id}`; if (tile.kind === "service") return `${tile.kind}:${tile.groupId}:${tile.id}`; return `${tile.kind}:${tile.id}`; }