flagon-io/g1t

public

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

g1t/apps/status/src/components.ts

215 lines7,327 bytesCodeBlame
1/**
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 /** Git storage, through the repos service binding: how the store answered lately. */
42 | { kind: "storage" }
43 /** No check yet: the page says so rather than showing green. */
44 | { kind: "none" };
45
46export type ComponentInfo = {
47 key: string;
48 name: string;
49 address: string;
50 checks: string;
51 /** Whether g1t as a whole is down when this is. */
52 core: boolean;
53 check: Check;
54 /** Slower than this, it counts as degraded; `SLOW_MS` when absent. */
55 slowMs?: number;
56};
57
58/**
59 * The page-speed budget the status page holds the site to: the slower of a
60 * public project page and Explore, to the first byte of the answer, from a
61 * Cloudflare data centre. docs/PERFORMANCE.md has the targets.
62 */
63export const SPEED_BUDGET_MS = 800;
64
65/** A token no one holds: the API asks identity about it and refuses it. */
66export const NO_TOKEN = `g1t_${"0".repeat(40)}`;
67
68function host(url: string): string {
69 try {
70 return new URL(url).host;
71 } catch {
72 return url;
73 }
74}
75
76const trim = (url: string | undefined) => (url ?? "").trim().replace(/\/+$/, "");
77
78/** Git storage counts as degraded when its calls took longer than this on average. */
79export const STORAGE_SLOW_MS = 1500;
80
81/** The parts, in the order the page lists them. `storage`: whether the repos service is bound. */
82export function components(vars: Partial<Targets>, billing = true, storage = false): ComponentInfo[] {
83 const site = trim(vars.SITE_URL);
84 const api = trim(vars.API_URL);
85 const mcp = trim(vars.MCP_URL);
86 const docs = trim(vars.DOCS_URL);
87 const pages = trim(vars.PAGES_URL);
88 const models = trim(vars.MODELS_URL);
89 const repo = (vars.PROBE_REPO ?? "").trim();
90 // What the page shows as the site's address: where people reach it.
91 const shown = host(trim(vars.PUBLIC_SITE_URL) || site);
92 const list: (ComponentInfo | null)[] = [
93 site
94 ? {
95 key: "site",
96 name: "Website and sign-in",
97 address: shown,
98 checks: api
99 ? "The sign-in page loading, and the account service answering an access token through the API."
100 : "The sign-in page loading.",
101 core: true,
102 check: {
103 kind: "http",
104 steps: [
105 { url: `${site}/login` },
106 ...(api ? [{ url: `${api}/v1/user`, headers: { authorization: `Bearer ${NO_TOKEN}` }, expect: 401 }] : []),
107 ],
108 },
109 }
110 : null,
111 api
112 ? {
113 key: "api",
114 name: "API",
115 address: host(api),
116 checks: "The API's front page.",
117 core: true,
118 check: { kind: "http", steps: [{ url: `${api}/` }] },
119 }
120 : null,
121 site && repo
122 ? {
123 key: "git",
124 name: "Git and repositories",
125 address: `${shown}/<owner>/<repo>.git`,
126 checks: "Listing the branches of a public repository over HTTPS, the first step of every clone.",
127 core: true,
128 check: { kind: "http", steps: [{ url: `${site}/${repo}.git/info/refs?service=git-upload-pack` }] },
129 }
130 : null,
131 storage && site
132 ? {
133 key: "storage",
134 name: "Git storage",
135 address: "Where every repository is kept",
136 checks: `How g1t's git storage answered over the last five minutes, as g1t saw it: failures, rate limits, and how long calls took. Rate limited, or slower than ${STORAGE_SLOW_MS} ms on average, counts as degraded.`,
137 core: false,
138 check: { kind: "storage" },
139 slowMs: STORAGE_SLOW_MS,
140 }
141 : null,
142 site && repo
143 ? {
144 key: "speed",
145 name: "Page speed",
146 address: `${shown}/${repo}`,
147 checks: `A public project page and Explore each answering within ${SPEED_BUDGET_MS} ms. Slower counts as degraded.`,
148 core: false,
149 check: { kind: "http", steps: [{ url: `${site}/${repo}` }, { url: `${site}/explore` }] },
150 slowMs: SPEED_BUDGET_MS,
151 }
152 : null,
153 mcp
154 ? {
155 key: "mcp",
156 name: "MCP server",
157 address: host(mcp),
158 checks: "The MCP server's description.",
159 core: false,
160 check: { kind: "http", steps: [{ url: `${mcp}/`, headers: { accept: "application/json" } }] },
161 }
162 : null,
163 docs
164 ? {
165 key: "docs",
166 name: "Documentation",
167 address: host(docs),
168 checks: "The documentation's front page.",
169 core: false,
170 check: { kind: "http", steps: [{ url: `${docs}/` }] },
171 }
172 : null,
173 pages
174 ? {
175 key: "deployments",
176 name: "Deployments",
177 address: `*.${host(pages)}`,
178 checks: `${host(pages)} answering. Each deployed app is not checked one by one.`,
179 core: false,
180 check: { kind: "http", steps: [{ url: `${pages}/` }] },
181 }
182 : null,
183 models
184 ? {
185 key: "agents",
186 name: "Agents' model proxy",
187 address: host(models),
188 checks: "The proxy agents reach their model through. The model providers behind it are not checked.",
189 core: false,
190 check: { kind: "http", steps: [{ url: `${models}/` }] },
191 }
192 : null,
193 models
194 ? {
195 key: "sandboxes",
196 name: "Sandboxes",
197 address: "Agents, checks, workflows and builds",
198 checks: "Starting a sandbox costs money and takes seconds, so it is not checked from here yet.",
199 core: false,
200 check: { kind: "none" },
201 }
202 : null,
203 billing && site
204 ? {
205 key: "billing",
206 name: "Billing",
207 address: `${shown}/<workspace>/-/billing`,
208 checks: "The billing service reading its price book. Stripe itself is not checked.",
209 core: false,
210 check: { kind: "billing" },
211 }
212 : null,
213 ];
214 return list.filter((c): c is ComponentInfo => c != null);
215}