g1t/apps/status/src/components.ts

199 lines6,540 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas1/**
2 * The parts of g1t the page lists, and how each is checked. Every address
3 * comes from the Worker's vars, so an installation of its own names its own
4 * hosts; a part whose address is empty is not part of that installation
5 * and is left off the page.
6 *
7 * Checks go over the public internet, as people reach g1t, so they measure
8 * what people see. Billing has no public address of its own, so it is the
9 * one part checked through a service binding, when there is one.
10 */
11
12/** The Worker's vars that say where things are. */
13export type Targets = {
14 /** The site: `https://g1t.sh`. */
15 SITE_URL: string;
16 /** The API: `https://api.g1t.sh`. */
17 API_URL: string;
18 MCP_URL: string;
19 DOCS_URL: string;
20 /** Where deployed apps live: `https://g1t.page`. */
21 PAGES_URL: string;
22 MODELS_URL: string;
23 /** A public repository that always exists, `owner/name`, to fetch refs of. */
24 PROBE_REPO: string;
25 /** The site as browsers reach it, when the checks reach it another way. */
26 PUBLIC_SITE_URL?: string;
27};
28
29/** One request a check makes, and the answer that means the part works. */
30export type Step = {
31 url: string;
32 headers?: Record<string, string>;
33 /** The status that means it works; any 2xx when absent. */
34 expect?: number;
35};
36
37export type Check =
38 | { kind: "http"; steps: Step[] }
39 /** Billing, through its binding: reading its price book. */
40 | { kind: "billing" }
41 /** No check yet: the page says so rather than showing green. */
42 | { kind: "none" };
43
44export type ComponentInfo = {
45 key: string;
46 name: string;
47 address: string;
48 checks: string;
49 /** Whether g1t as a whole is down when this is. */
50 core: boolean;
51 check: Check;
Fast pages, required checks on the branch, self-hosted runners, honest incidents52 /** Slower than this, it counts as degraded; `SLOW_MS` when absent. */
53 slowMs?: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas54};
55
Fast pages, required checks on the branch, self-hosted runners, honest incidents56/**
57 * The page-speed budget the status page holds the site to: the slower of a
58 * public project page and Explore, to the first byte of the answer, from a
59 * Cloudflare data centre. docs/PERFORMANCE.md has the targets.
60 */
61export const SPEED_BUDGET_MS = 800;
62
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas63/** A token no one holds: the API asks identity about it and refuses it. */
64export const NO_TOKEN = `g1t_${"0".repeat(40)}`;
65
66function host(url: string): string {
67 try {
68 return new URL(url).host;
69 } catch {
70 return url;
71 }
72}
73
74const trim = (url: string | undefined) => (url ?? "").trim().replace(/\/+$/, "");
75
76/** The parts, in the order the page lists them. */
77export function components(vars: Partial<Targets>, billing = true): ComponentInfo[] {
78 const site = trim(vars.SITE_URL);
79 const api = trim(vars.API_URL);
80 const mcp = trim(vars.MCP_URL);
81 const docs = trim(vars.DOCS_URL);
82 const pages = trim(vars.PAGES_URL);
83 const models = trim(vars.MODELS_URL);
84 const repo = (vars.PROBE_REPO ?? "").trim();
85 // What the page shows as the site's address: where people reach it.
86 const shown = host(trim(vars.PUBLIC_SITE_URL) || site);
87 const list: (ComponentInfo | null)[] = [
88 site
89 ? {
90 key: "site",
91 name: "Website and sign-in",
92 address: shown,
93 checks: api
94 ? "The sign-in page loading, and the account service answering an access token through the API."
95 : "The sign-in page loading.",
96 core: true,
97 check: {
98 kind: "http",
99 steps: [
100 { url: `${site}/login` },
101 ...(api ? [{ url: `${api}/v1/user`, headers: { authorization: `Bearer ${NO_TOKEN}` }, expect: 401 }] : []),
102 ],
103 },
104 }
105 : null,
106 api
107 ? {
108 key: "api",
109 name: "API",
110 address: host(api),
111 checks: "The API's front page.",
112 core: true,
113 check: { kind: "http", steps: [{ url: `${api}/` }] },
114 }
115 : null,
116 site && repo
117 ? {
118 key: "git",
119 name: "Git and repositories",
120 address: `${shown}/<owner>/<repo>.git`,
121 checks: "Listing the branches of a public repository over HTTPS, the first step of every clone.",
122 core: true,
123 check: { kind: "http", steps: [{ url: `${site}/${repo}.git/info/refs?service=git-upload-pack` }] },
124 }
125 : null,
Fast pages, required checks on the branch, self-hosted runners, honest incidents126 site && repo
127 ? {
128 key: "speed",
129 name: "Page speed",
130 address: `${shown}/${repo}`,
131 checks: `A public project page and Explore each answering within ${SPEED_BUDGET_MS} ms. Slower counts as degraded.`,
132 core: false,
133 check: { kind: "http", steps: [{ url: `${site}/${repo}` }, { url: `${site}/explore` }] },
134 slowMs: SPEED_BUDGET_MS,
135 }
136 : null,
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas137 mcp
138 ? {
139 key: "mcp",
140 name: "MCP server",
141 address: host(mcp),
142 checks: "The MCP server's description.",
143 core: false,
144 check: { kind: "http", steps: [{ url: `${mcp}/`, headers: { accept: "application/json" } }] },
145 }
146 : null,
147 docs
148 ? {
149 key: "docs",
150 name: "Documentation",
151 address: host(docs),
152 checks: "The documentation's front page.",
153 core: false,
154 check: { kind: "http", steps: [{ url: `${docs}/` }] },
155 }
156 : null,
157 pages
158 ? {
159 key: "deployments",
160 name: "Deployments",
161 address: `*.${host(pages)}`,
162 checks: `${host(pages)} answering. Each deployed app is not checked one by one.`,
163 core: false,
164 check: { kind: "http", steps: [{ url: `${pages}/` }] },
165 }
166 : null,
167 models
168 ? {
169 key: "agents",
170 name: "Agents' model proxy",
171 address: host(models),
172 checks: "The proxy agents reach their model through. The model providers behind it are not checked.",
173 core: false,
174 check: { kind: "http", steps: [{ url: `${models}/` }] },
175 }
176 : null,
177 models
178 ? {
179 key: "sandboxes",
180 name: "Sandboxes",
181 address: "Agents, checks, workflows and builds",
182 checks: "Starting a sandbox costs money and takes seconds, so it is not checked from here yet.",
183 core: false,
184 check: { kind: "none" },
185 }
186 : null,
187 billing && site
188 ? {
189 key: "billing",
190 name: "Billing",
191 address: `${shown}/<workspace>/-/billing`,
192 checks: "The billing service reading its price book. Stripe itself is not checked.",
193 core: false,
194 check: { kind: "billing" },
195 }
196 : null,
197 ];
198 return list.filter((c): c is ComponentInfo => c != null);
199}