export interface DashboardRefreshPauseState { visibilityState: DocumentVisibilityState; online: boolean; } export type DashboardTileReference = | { kind: "telemetry"; id: string } | { kind: "service"; groupId: string; id: string } | { kind: "module"; id: string } | { kind: "status"; stripId: string; id: string }; type SnapshotMetricValue = Record; export type DashboardTileSnapshotItem = { detail?: string; id: string; label?: string; severity?: string; value?: SnapshotMetricValue | string; } & Record; export type DashboardTileSnapshotResponse = | { state: "ready"; tile: DashboardTileReference; item: DashboardTileSnapshotItem; } | { state: "not_found"; tile: DashboardTileReference; message: string; } | { state: "disabled"; tile: DashboardTileReference; message: string; }; export function shouldPauseDashboardRefresh( state: DashboardRefreshPauseState, ): boolean { return state.visibilityState !== "visible" || !state.online; } export function createDashboardRequestAborter() { let shellController: AbortController | undefined; let tileController: AbortController | undefined; function abortController(controller: AbortController | undefined) { if (controller && !controller.signal.aborted) { controller.abort(); } } return { beginShellRun(): AbortSignal { abortController(shellController); abortController(tileController); shellController = new AbortController(); tileController = undefined; return shellController.signal; }, beginTileRun(): AbortSignal { abortController(tileController); tileController = new AbortController(); return tileController.signal; }, abortActiveRequests(): void { abortController(shellController); abortController(tileController); shellController = undefined; tileController = undefined; }, }; } type DashboardRefreshEventTarget = Pick< EventTarget, "addEventListener" | "removeEventListener" >; export interface DashboardRefreshLifecycleOptions { documentTarget: DashboardRefreshEventTarget; windowTarget: DashboardRefreshEventTarget; loadDashboard: () => void | Promise; pauseRefreshes: () => void; refreshPaused: () => boolean; } export function attachDashboardRefreshLifecycle( options: DashboardRefreshLifecycleOptions, ): () => void { function handleRefreshLifecycleChange() { if (options.refreshPaused()) { options.pauseRefreshes(); return; } void options.loadDashboard(); } function handlePageHide() { options.pauseRefreshes(); } options.documentTarget.addEventListener( "visibilitychange", handleRefreshLifecycleChange, ); options.windowTarget.addEventListener("online", handleRefreshLifecycleChange); options.windowTarget.addEventListener("offline", handleRefreshLifecycleChange); options.windowTarget.addEventListener("pagehide", handlePageHide); return () => { options.documentTarget.removeEventListener( "visibilitychange", handleRefreshLifecycleChange, ); options.windowTarget.removeEventListener("online", handleRefreshLifecycleChange); options.windowTarget.removeEventListener("offline", handleRefreshLifecycleChange); options.windowTarget.removeEventListener("pagehide", handlePageHide); }; } export interface DashboardHydrationQueueOptions { concurrency: number; hydrate: (item: TItem) => Promise | void; items: TItem[]; signal: AbortSignal; } export async function runDashboardHydrationQueue( options: DashboardHydrationQueueOptions, ): Promise { const concurrency = Math.max(1, Math.floor(options.concurrency)); let nextIndex = 0; async function worker() { while (!options.signal.aborted) { const item = options.items[nextIndex]; nextIndex += 1; if (item === undefined) return; await options.hydrate(item); } } const workerCount = Math.min(concurrency, options.items.length); await Promise.all( Array.from({ length: workerCount }, () => worker()), ); } const dashboardTileBackoffDelaysMs = [15_000, 30_000, 60_000, 120_000]; export function createDashboardTileBackoff() { const failures = new Map(); return { canAttempt(key: string, now = Date.now()): boolean { const failure = failures.get(key); return !failure || now >= failure.nextAttemptAt; }, recordFailure(key: string, now = Date.now()): void { const previousAttempts = failures.get(key)?.attempts || 0; const attempts = previousAttempts + 1; const delay = dashboardTileBackoffDelaysMs[ Math.min(attempts - 1, dashboardTileBackoffDelaysMs.length - 1) ]; failures.set(key, { attempts, nextAttemptAt: now + delay, }); }, recordSuccess(key: string): void { failures.delete(key); }, }; } interface DashboardTileSnapshotRecord { item: DashboardTileSnapshotItem; savedAt: number; tile: DashboardTileReference; } interface DashboardTileSnapshotPayload { currentRevisionId: string; schemaVersion: string; tiles: DashboardTileSnapshotRecord[]; version: 1; } export interface DashboardTileSnapshotStoreContext { currentRevisionId: string; schemaVersion: string; } export interface DashboardTileSnapshotStoreOptions { now?: () => number; } export interface RestoredDashboardTileSnapshot { ageMs: number; response: Extract; } const dashboardTileSnapshotStorageKey = "dimensionlab.dashboard.tiles.v1"; export function createDashboardTileSnapshotStore( storage: Storage | undefined, options: DashboardTileSnapshotStoreOptions = {}, ) { const now = options.now || Date.now; function read(): DashboardTileSnapshotPayload | null { if (!storage) return null; try { const serialized = storage.getItem(dashboardTileSnapshotStorageKey); if (!serialized) return null; const payload = JSON.parse(serialized) as Partial; if ( payload.version !== 1 || typeof payload.currentRevisionId !== "string" || typeof payload.schemaVersion !== "string" || !Array.isArray(payload.tiles) ) { return null; } return { currentRevisionId: payload.currentRevisionId, schemaVersion: payload.schemaVersion, tiles: payload.tiles.filter(isDashboardTileSnapshotRecord), version: 1, }; } catch { return null; } } function write(payload: DashboardTileSnapshotPayload): void { if (!storage) return; try { storage.setItem(dashboardTileSnapshotStorageKey, JSON.stringify(payload)); } catch { // Best-effort warm-start cache; quota and privacy failures are non-fatal. } } function matchingPayload( context: DashboardTileSnapshotStoreContext, ): DashboardTileSnapshotPayload { const payload = read(); if ( payload && payload.currentRevisionId === context.currentRevisionId && payload.schemaVersion === context.schemaVersion ) { return payload; } return { currentRevisionId: context.currentRevisionId, schemaVersion: context.schemaVersion, tiles: [], version: 1, }; } function saveReadyTile( input: DashboardTileSnapshotStoreContext & { response: Extract; }, ): void { const payload = matchingPayload(input); const key = dashboardTileSnapshotKey(input.response.tile); const nextRecord: DashboardTileSnapshotRecord = { item: input.response.item, savedAt: now(), tile: input.response.tile, }; payload.tiles = [ nextRecord, ...payload.tiles.filter((record) => dashboardTileSnapshotKey(record.tile) !== key ), ]; write(payload); } return { restore(context: DashboardTileSnapshotStoreContext): RestoredDashboardTileSnapshot[] { const payload = read(); if ( !payload || payload.currentRevisionId !== context.currentRevisionId || payload.schemaVersion !== context.schemaVersion ) { return []; } const restoredAt = now(); return payload.tiles.map((record) => ({ ageMs: Math.max(0, restoredAt - record.savedAt), response: { state: "ready", tile: record.tile, item: { ...record.item, detail: staleDashboardTileDetail(record.item.detail, restoredAt - record.savedAt), severity: "stale", }, }, })); }, saveReadyTile, saveTile(input: DashboardTileSnapshotStoreContext & { response: DashboardTileSnapshotResponse; }): void { if (input.response.state === "ready") { saveReadyTile({ currentRevisionId: input.currentRevisionId, response: input.response, schemaVersion: input.schemaVersion, }); } }, }; } 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 { return typeof value === "object" && value !== null; } function staleDashboardTileDetail( detail: string | undefined, ageMs: number, ): string | undefined { if (!detail) return detail; const ageSeconds = Math.max(0, Math.floor(ageMs / 1_000)); return ageSeconds > 0 ? `${detail} - stale ${ageSeconds}s` : detail; }