Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

35 linesCodeBlameRaw
1/**
2 * Each part of a page loads on its own, and one that fails says so in its
3 * own place, the way a form says what is wrong beside the field. A loader
4 * reads what the page is about as usual: when that fails, the page fails
5 * (routes/page-boundary.tsx). Every part beside it (a sidebar card, a
6 * panel, a count) is read through `part`, which keeps a failure as
7 * `Failed` instead of throwing, and the part shows `Unavailable` in its
8 * place (components/boundary.tsx) while the rest of the page stays up.
9 *
10 * Only failures are caught: a service that did not answer, or answered
11 * with a 5xx. A refusal or a 404 is an answer (`{ ok: false }`), which the
12 * page reads as it always has.
13 */
14
15/** A part that could not be loaded, by what it is. Plain data, so a loader can send it. */
16export type Failed = { failed: true; what: string };
17
18/** `work`, or `Failed` when it throws; logged, so the failure is still seen. */
19export async function part<T>(work: Promise<T> | T, what: string): Promise<T | Failed> {
20 try {
21 return await work;
22 } catch (error) {
23 console.warn(`g1t: ${what} could not be loaded:`, error);
24 return { failed: true, what };
25 }
26}
27
28export function isFailed(value: unknown): value is Failed {
29 return typeof value === "object" && value !== null && (value as Failed).failed === true && typeof (value as Failed).what === "string";
30}
31
32/** The value, or `fallback` when it failed: for a part that can quietly do without. */
33export function orElse<T, F>(value: T | Failed, fallback: F): T | F {
34 return isFailed(value) ? fallback : value;
35}