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()), ); } export interface DashboardViewportHydrationQueueOptions { batchSize?: number; collectVisibleModelIds: () => Promise>; concurrency: number; getModelId: (item: TItem) => string; hydrate: (item: TItem) => Promise | void; hydrateBatch?: (items: TItem[]) => Promise | void; items: TItem[]; onAllItemsSettled?: () => void; onVisibleItemsSettled?: () => void; signal: AbortSignal; waitForIdle: () => Promise; } export async function runViewportAwareDashboardHydrationQueue( options: DashboardViewportHydrationQueueOptions, ): Promise { const visibleModelIds = await options.collectVisibleModelIds(); if (options.signal.aborted) return; const { visible, deferred } = splitDashboardHydrationItemsByVisibility({ getModelId: options.getModelId, items: options.items, visibleModelIds, }); await runDashboardHydrationItems(options, visible); if (options.signal.aborted) return; options.onVisibleItemsSettled?.(); if (!deferred.length) { options.onAllItemsSettled?.(); return; } await options.waitForIdle(); if (options.signal.aborted) return; await runDashboardHydrationItems(options, deferred); options.onAllItemsSettled?.(); } async function runDashboardHydrationItems( options: DashboardViewportHydrationQueueOptions, items: TItem[], ): Promise { if (!options.hydrateBatch) { await runDashboardHydrationQueue({ concurrency: options.concurrency, hydrate: options.hydrate, items, signal: options.signal, }); return; } await runDashboardHydrationBatchQueue({ batchSize: options.batchSize ?? options.concurrency, hydrateBatch: options.hydrateBatch, items, signal: options.signal, }); } export async function runDashboardHydrationBatchQueue(options: { batchSize: number; hydrateBatch: (items: TItem[]) => Promise | void; items: TItem[]; signal: AbortSignal; }): Promise { const batchSize = Math.max(1, Math.floor(options.batchSize)); for (let index = 0; index < options.items.length; index += batchSize) { if (options.signal.aborted) return; await options.hydrateBatch(options.items.slice(index, index + batchSize)); } } export function splitDashboardHydrationItemsByVisibility(options: { getModelId: (item: TItem) => string; items: TItem[]; visibleModelIds: ReadonlySet; }): { deferred: TItem[]; visible: TItem[]; } { const visible: TItem[] = []; const deferred: TItem[] = []; for (const item of options.items) { if (options.visibleModelIds.has(options.getModelId(item))) { visible.push(item); } else { deferred.push(item); } } return { visible, deferred }; } export interface DashboardModelElement { getAttribute(name: string): string | null; } export interface DashboardViewportElementSource { querySelectorAll(selector: string): ArrayLike; } export interface DashboardIntersectionEntry { intersectionRatio?: number; isIntersecting: boolean; target: DashboardModelElement; } export interface DashboardIntersectionObserver { disconnect(): void; observe(element: DashboardModelElement): void; } export type DashboardIntersectionObserverFactory = ( callback: (entries: DashboardIntersectionEntry[]) => void, ) => DashboardIntersectionObserver; type DashboardTimerHandle = ReturnType; export interface DashboardVisibleModelIdCollectorOptions { clearTimeout?: (handle: DashboardTimerHandle) => void; createObserver?: DashboardIntersectionObserverFactory; documentTarget: DashboardViewportElementSource; modelIds: Iterable; setTimeout?: (callback: () => void, timeoutMs: number) => DashboardTimerHandle; signal: AbortSignal; timeoutMs?: number; } export async function collectVisibleDashboardModelIds( options: DashboardVisibleModelIdCollectorOptions, ): Promise> { const targetIds = new Set(options.modelIds); if (!targetIds.size || options.signal.aborted) return new Set(); const elements = Array.from( options.documentTarget.querySelectorAll("[data-model-id]"), ).filter((element) => { const modelId = element.getAttribute("data-model-id"); return modelId ? targetIds.has(modelId) : false; }); if (!elements.length) return new Set(); if (!options.createObserver) return targetIds; const createObserver = options.createObserver; const setTimer = options.setTimeout || ((callback: () => void, timeoutMs: number) => globalThis.setTimeout(callback, timeoutMs)); const clearTimer = options.clearTimeout || ((handle: DashboardTimerHandle) => globalThis.clearTimeout(handle)); const timeoutMs = options.timeoutMs ?? 80; return new Promise((resolve) => { const visibleModelIds = new Set(); let settled = false; let timeoutHandle: DashboardTimerHandle | undefined; let observer: DashboardIntersectionObserver | undefined; function cleanup() { if (timeoutHandle !== undefined) { clearTimer(timeoutHandle); } observer?.disconnect(); options.signal.removeEventListener("abort", finish); } function finish() { if (settled) return; settled = true; cleanup(); resolve(visibleModelIds); } observer = createObserver((entries) => { for (const entry of entries) { const modelId = entry.target.getAttribute("data-model-id"); if ( modelId && targetIds.has(modelId) && (entry.isIntersecting || (entry.intersectionRatio ?? 0) > 0) ) { visibleModelIds.add(modelId); } } }); for (const element of elements) { observer.observe(element); } options.signal.addEventListener("abort", finish, { once: true }); timeoutHandle = setTimer(finish, timeoutMs); }); } export interface DashboardHydrationIdleOptions { cancelIdleCallback?: (handle: number) => void; clearTimeout?: (handle: DashboardTimerHandle) => void; requestIdleCallback?: ( callback: () => void, options?: { timeout?: number }, ) => number; setTimeout?: (callback: () => void, timeoutMs: number) => DashboardTimerHandle; signal: AbortSignal; timeoutMs?: number; } export async function waitForDashboardHydrationIdle( options: DashboardHydrationIdleOptions, ): Promise { if (options.signal.aborted) return; const setTimer = options.setTimeout || ((callback: () => void, timeoutMs: number) => globalThis.setTimeout(callback, timeoutMs)); const clearTimer = options.clearTimeout || ((handle: DashboardTimerHandle) => globalThis.clearTimeout(handle)); await new Promise((resolve) => { let settled = false; let idleHandle: number | undefined; let timeoutHandle: DashboardTimerHandle | undefined; function cleanup() { if (idleHandle !== undefined) { options.cancelIdleCallback?.(idleHandle); } if (timeoutHandle !== undefined) { clearTimer(timeoutHandle); } options.signal.removeEventListener("abort", finish); } function finish() { if (settled) return; settled = true; cleanup(); resolve(); } options.signal.addEventListener("abort", finish, { once: true }); if (options.requestIdleCallback) { idleHandle = options.requestIdleCallback(finish, { timeout: options.timeoutMs ?? 1_000, }); } else { timeoutHandle = setTimer(finish, 0); } }); } export interface DashboardRefreshDelayOptions { failureMultiplierLimit?: number; jitterRatio?: number; random?: () => number; } export function createDashboardRefreshDelay( options: DashboardRefreshDelayOptions = {}, ) { const random = options.random || Math.random; const jitterRatio = options.jitterRatio ?? 0.1; const failureMultiplierLimit = options.failureMultiplierLimit ?? 8; let consecutiveFailures = 0; return { nextDelayMs(baseDelayMs: number): number { const failureMultiplier = consecutiveFailures ? Math.min(2 ** consecutiveFailures, failureMultiplierLimit) : 1; const jitterFactor = 1 + ((random() * 2) - 1) * jitterRatio; return Math.max(0, Math.round(baseDelayMs * failureMultiplier * jitterFactor)); }, recordFailure(): void { consecutiveFailures += 1; }, recordSuccess(): void { consecutiveFailures = 0; }, }; } export interface DashboardPerformanceMarkOptions { mark?: (name: string) => void; } export const dashboardPerformanceMarks = { allTilesSettled: "dashboard:all-tiles-settled", firstTileReady: "dashboard:first-tile-ready", shellLoad: "dashboard:shell-load", visibleTilesReady: "dashboard:visible-tiles-ready", } as const; export function createDashboardPerformanceMarks( options: DashboardPerformanceMarkOptions = {}, ) { const mark = options.mark || globalThis.performance?.mark?.bind(globalThis.performance); let firstTileReadyMarked = false; function safeMark(name: string) { try { mark?.(name); } catch { // Performance marks are diagnostics only. } } return { markAllTilesSettled(): void { safeMark(dashboardPerformanceMarks.allTilesSettled); }, markFirstTileReady(): void { if (firstTileReadyMarked) return; firstTileReadyMarked = true; safeMark(dashboardPerformanceMarks.firstTileReady); }, markShellLoad(): void { firstTileReadyMarked = false; safeMark(dashboardPerformanceMarks.shellLoad); }, markVisibleTilesReady(): void { safeMark(dashboardPerformanceMarks.visibleTilesReady); }, }; } 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.tile, 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( tile: DashboardTileReference, value: unknown, ): value is DashboardTileSnapshotItem { if (!isSnapshotRecord(value) || value.id !== tile.id) return false; switch (tile.kind) { case "telemetry": return ( typeof value.label === "string" && isMetricValue(value.value) && isSeverity(value.severity) && isOptionalString(value.detail) && isOptionalString(value.description) && isOptionalString(value.icon) && isOptionalNumberArray(value.sparkline) ); case "service": return ( typeof value.label === "string" && typeof value.description === "string" && isSeverity(value.severity) && isOptionalString(value.detail) && isOptionalString(value.icon) && isOptionalLink(value.link) ); case "module": return ( (value.kind === "summary" || value.kind === "weather" || value.kind === "custom") && isOptionalString(value.title) && isOptionalString(value.label) && isOptionalString(value.value) && isOptionalString(value.detail) && isOptionalString(value.icon) && (value.severity === undefined || isSeverity(value.severity)) ); case "status": return ( typeof value.label === "string" && typeof value.value === "string" && isOptionalLink(value.link) && (value.severity === undefined || isSeverity(value.severity)) ); } } function isSnapshotRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } function isMetricValue(value: unknown): boolean { if (!isSnapshotRecord(value) || typeof value.kind !== "string") return false; if (value.kind === "text") { return ( typeof value.value === "string" && isOptionalString(value.unit) ); } const numericKinds = ["bytes", "latency", "number", "percent", "temperature"]; if (!numericKinds.includes(value.kind)) return false; if (typeof value.value !== "number" || !Number.isFinite(value.value)) return false; if (value.kind === "percent" && (value.value < 0 || value.value > 100)) { return false; } const precision = value.precision; return ( isOptionalString(value.unit) && (precision === undefined || (typeof precision === "number" && Number.isInteger(precision) && precision >= 0 && precision <= 4)) ); } function isSeverity(value: unknown): boolean { return ( value === "neutral" || value === "ok" || value === "warning" || value === "danger" || value === "stale" || value === "unavailable" ); } function isOptionalString(value: unknown): boolean { return value === undefined || typeof value === "string"; } function isOptionalNumberArray(value: unknown): boolean { return ( value === undefined || (Array.isArray(value) && value.every((item) => typeof item === "number" && Number.isFinite(item))) ); } function isOptionalLink(value: unknown): boolean { return ( value === undefined || (isSnapshotRecord(value) && typeof value.href === "string" && isOptionalString(value.label) && (value.external === undefined || typeof value.external === "boolean")) ); } 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; }