Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 1x 7x 7x 5x 4x 1x 3x 3x | /**
* Status of a fetched JSON resource. The four states cover every
* decision a host-side panel needs to make:
*
* - `loading` — initial / in-flight; render a spinner placeholder.
* - `ready` — request resolved with parsed JSON in `data`.
* - `missing` — server returned 404; the artifact does not exist
* yet (e.g. compliance reports for a component the
* CLI has not seen). Distinct from `error` so hosts
* can render a remediation hint instead of a banner.
* - `error` — non-OK response, network failure, or JSON parse
* error. `error` carries a human-readable message.
*/
export type FetchStatus = 'loading' | 'ready' | 'missing' | 'error';
/** Discriminated union return shape; narrow on `status` at the call site. */
export type FetchResult<T> =
| { status: 'ready'; data: T }
| { status: 'missing' }
| { status: 'error'; error: string };
/**
* Initial state to seed `useState` calls. Exported so consumers don't
* have to magic-string the literal each time.
*/
export const FETCH_LOADING = { status: 'loading' as const };
/**
* Fetch a JSON resource and resolve to a `FetchResult`. Never rejects —
* exceptions and non-OK responses fold into `{ status: 'error', … }`
* so React render trees can switch off `status` without try/catch at
* the call site.
*
* Generic over the JSON payload type. Pass a type argument when the
* caller has a stable schema for the resource:
*
* const r = await fetchJson<ComponentComplianceReport>(url);
*
* `cache: 'no-cache'` is hard-coded because every known consumer is a
* dev-loop panel that re-fetches on file change. If a future caller
* needs caching, parameterize the second arg.
*/
export async function fetchJson<T>(url: string): Promise<FetchResult<T>> {
try {
const res = await fetch(url, { cache: 'no-cache' });
if (res.status === 404) return { status: 'missing' };
if (!res.ok) {
return { status: 'error', error: `HTTP ${res.status} while loading ${url}.` };
}
return { status: 'ready', data: (await res.json()) as T };
} catch (e) {
return {
status: 'error',
error: e instanceof Error ? e.message : String(e),
};
}
}
|