| 1 | export interface ProcessDiagnosticsSnapshot { |
| 2 | scope: "electron"; |
| 3 | growth?: { pid: number; type: string; metric: "private" | "working-set"; baselineMb: number; currentMb: number; durationMs: number }[]; |
| 4 | samples: { |
| 5 | ageMs: number; |
| 6 | intervalMs: number | null; |
| 7 | truncated?: boolean; |
| 8 | processes: { pid: number; type: string; cpuPercent: number | null; workingSetMb: number | null; privateMb: number | null }[]; |
| 9 | }[]; |
| 10 | } |
| 11 | |
| 12 | export interface RendererProfileResult { |
| 13 | status: "recording" | "captured" | "inactive" | "busy" | "cooldown" | "limit" | "unavailable" | "cancelled" | "failed"; |
| 14 | durationMs?: number; |
| 15 | frames?: { label: string; samples: number; selfMs: number }[]; |
| 16 | } |
| 17 | export interface NativePerformanceActions { |
| 18 | captureRendererProfile?(requestId?: string): Promise<RendererProfileResult>; |
| 19 | cancelRendererProfile?(requestId?: string): Promise<unknown>; |
| 20 | exportHeapSnapshot?(): Promise<{ status: "saved" | "cancelled" | "busy" | "unavailable" | "failed" }>; |
| 21 | } |
| 22 | |
| 23 | // Reporting must still work with an older shell, a rejected IPC or a hung host. |
| 24 | export async function boundedDiagnostics<T>(read: () => Promise<T>, timeoutMs = 750): Promise<T | undefined> { |
| 25 | let cancel = () => {}; |
| 26 | try { |
| 27 | return await Promise.race([ |
| 28 | Promise.resolve().then(read).catch(() => undefined), |
| 29 | new Promise<undefined>((resolve) => { const timer = setTimeout(resolve, timeoutMs); cancel = () => clearTimeout(timer); }), |
| 30 | ]); |
| 31 | } finally { cancel(); } |
| 32 | } |
| 33 |