Skip to content
220 linesCodeBlameRaw

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.

Deployments: a preview for every pull request, production on g1t.page1/**
2 * The dispatcher for g1t.page: every app deployed by g1t is served here.
3 *
4 * The hostname's first label is the app's script name in the Workers for
Projects live: fixes from walking them end to end5 * Platforms namespace (`web-git-fix-login-acme.g1t.page` is the fix-login
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas6 * branch's preview of acme's web project), so the app is fetched by name
7 * and runs only for as long as it answers. An app no one visits runs
Merge branch 'worktree-agent-ab9543c492a7ed481' into spend-guardrails8 * nothing and costs nothing. Each request it serves is held to
9 * `APP_LIMITS`, so one app cannot spend without bound. The one lookup is for an address an app
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas10 * had before its project moved: `DOMAINS` holds a redirect under the old
11 * hostname for as long as the old name is held, and it is followed before
12 * anything the old script would answer (such as a paused notice).
Deployments: a preview for every pull request, production on g1t.page13 *
Agents and memory, checks and conflicts, profiles, slug renames, custom domains14 * Any other hostname is a project's custom domain, reaching here through
15 * Cloudflare for SaaS: the `DOMAINS` KV namespace, written by the
16 * deployments service, names its app, or the hostname it redirects to.
17 *
Deployments: a preview for every pull request, production on g1t.page18 * Kept apart from g1t.sh, so apps share no cookies or origin with the site
19 * people sign in to.
20 */
21
Merge branch 'worktree-agent-ab9543c492a7ed481' into spend-guardrails22import { APP_LIMITS, DOMAIN, FALLBACK, overLimits, parseEntry, redirectTo, route, type DomainEntry } from "./route.ts";
Agents and memory, checks and conflicts, profiles, slug renames, custom domains23
Deployments: a preview for every pull request, production on g1t.page24type Env = {
25 APPS: DispatchNamespace;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas26 /** Custom hostname, or an app's old g1t.page hostname, to `{ script, redirect }`. */
Agents and memory, checks and conflicts, profiles, slug renames, custom domains27 DOMAINS?: KVNamespace;
Deployments: a preview for every pull request, production on g1t.page28};
29
Agents and memory, checks and conflicts, profiles, slug renames, custom domains30/** How long a custom hostname's entry is kept in this isolate and at the edge. */
31const ENTRY_TTL_MS = 60 * 1000;
32const entries = new Map<string, { at: number; entry: DomainEntry | null }>();
Deployments: a preview for every pull request, production on g1t.page33
Agents and memory, checks and conflicts, profiles, slug renames, custom domains34function page(status: number, title: string, body: string, site = DOMAIN): Response {
Deployments: a preview for every pull request, production on g1t.page35 const html = `<!doctype html>
36<html lang="en">
37<head>
38<meta charset="utf-8">
39<meta name="viewport" content="width=device-width, initial-scale=1">
40<meta name="robots" content="noindex">
Agents and memory, checks and conflicts, profiles, slug renames, custom domains41<title>${escape(title)} · ${escape(site)}</title>
Deployments: a preview for every pull request, production on g1t.page42<style>
43 :root { color-scheme: dark; --bg: #121214; --fg: #ececf1; --muted: #9a9aa6; --accent: #b4a7f5; }
44 body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: var(--bg); color: var(--fg);
45 font: 16px/1.6 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; padding: 0 16px; }
46 main { max-width: 32rem; }
47 h1 { font-size: 1.5rem; margin: 0 0 .5rem; letter-spacing: -.01em; }
48 p { color: var(--muted); margin: .5rem 0; }
49 a { color: var(--accent); }
50 code { font: .9em ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--fg); }
51</style>
52</head>
Agents and memory, checks and conflicts, profiles, slug renames, custom domains53<body><main><h1>${escape(title)}</h1>${body}</main></body>
Deployments: a preview for every pull request, production on g1t.page54</html>`;
55 return new Response(html, {
56 status,
Agents and memory, checks and conflicts, profiles, slug renames, custom domains57 headers: { "content-type": "text/html; charset=utf-8", "x-robots-tag": "noindex", "cache-control": "no-store" },
Deployments: a preview for every pull request, production on g1t.page58 });
59}
60
61function escape(text: string): string {
62 return text.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
63}
64
Agents and memory, checks and conflicts, profiles, slug renames, custom domains65/** A custom hostname's entry: from this isolate, else KV (cached at the edge too). */
66async function lookup(env: Env, hostname: string): Promise<DomainEntry | null> {
67 const cached = entries.get(hostname);
68 if (cached && Date.now() - cached.at < ENTRY_TTL_MS) return cached.entry;
69 const value = env.DOMAINS ? await env.DOMAINS.get(hostname, { type: "json", cacheTtl: ENTRY_TTL_MS / 1000 }) : null;
70 const entry = parseEntry(value);
71 entries.set(hostname, { at: Date.now(), entry });
72 if (entries.size > 5000) entries.delete(entries.keys().next().value!);
73 return entry;
74}
75
76/** Runs the app `script` for the request; `shown` is the address named in its error pages. */
77async function dispatch(env: Env, request: Request, script: string, shown: string, missing: () => Response): Promise<Response> {
78 let app: Fetcher;
79 try {
Merge branch 'worktree-agent-ab9543c492a7ed481' into spend-guardrails80 app = env.APPS.get(script, {}, { limits: APP_LIMITS });
Agents and memory, checks and conflicts, profiles, slug renames, custom domains81 } catch {
82 return missing();
83 }
84 try {
85 return await app.fetch(request);
86 } catch (error) {
87 if (/worker not found|script not found|does not exist/i.test(String(error))) return missing();
Merge branch 'worktree-agent-ab9543c492a7ed481' into spend-guardrails88 if (overLimits(error)) {
89 return page(
90 503,
91 "The app went over its limits",
92 `<p>The app at <code>${escape(shown)}</code> used more than ${APP_LIMITS.cpuMs} ms of CPU time, or made more than ${APP_LIMITS.subRequests} requests of its own, answering this request.</p>`,
93 shown,
94 );
95 }
Agents and memory, checks and conflicts, profiles, slug renames, custom domains96 return page(
97 502,
98 "The app failed",
99 `<p>The app at <code>${escape(shown)}</code> threw an error before it could answer.</p>`,
100 shown,
101 );
102 }
103}
104
Deployments: a preview for every pull request, production on g1t.page105export default {
106 async fetch(request: Request, env: Env): Promise<Response> {
Agents and memory, checks and conflicts, profiles, slug renames, custom domains107 const host = new URL(request.url).hostname;
108 const where = route(host);
109 switch (where.kind) {
110 case "home":
111 return page(
112 200,
113 "g1t.page",
114 `<p>Apps deployed by <a href="https://g1t.sh">g1t</a>: every pull request's preview, and each repository's production.</p>
115 <p><a href="https://docs.g1t.sh/guides/deployments/">How deployments work</a></p>`,
116 );
117 case "fallback":
118 return page(
119 200,
120 "Custom domains on g1t",
121 `<p>Point a custom domain here, with a CNAME to <code>${FALLBACK}</code>, to serve a project's production on it. Add the domain first, under the project's Settings, Deployments, on g1t.</p>
122 <p><a href="https://docs.g1t.sh/guides/deployments/#custom-domains">How custom domains work</a></p>`,
123 );
124 case "invalid":
125 return page(404, "Nothing here", "<p>This is not the address of an app on g1t.page.</p>");
126 case "custom":
127 return custom(request, env, where.hostname);
128 case "app": {
129 const label = where.label;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas130 // An address the app had before its project moved (its workspace or
131 // repository was renamed or transferred) redirects to where it is
132 // now, whatever the app it named answers, paused or not.
133 const moved = await appRedirect(request, env, label);
134 if (moved) return moved;
Agents and memory, checks and conflicts, profiles, slug renames, custom domains135 let response = await dispatch(env, request, label, `${label}.${DOMAIN}`, () => missing(label));
136 // Previews are for the people reviewing a change, not search engines.
137 if (isPreview(label)) {
138 response = new Response(response.body, response);
139 response.headers.set("x-robots-tag", "noindex");
140 }
141 return response;
142 }
Deployments: a preview for every pull request, production on g1t.page143 }
144 },
145} satisfies ExportedHandler<Env>;
146
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas147/**
148 * The redirect for an app's old address, if the deployments service left
149 * one (in `DOMAINS`, under the old hostname, as `{ script, redirect }`),
150 * else null. A lookup that fails serves the app as it is rather than an
151 * error.
152 */
153async function appRedirect(request: Request, env: Env, label: string): Promise<Response | null> {
154 const hostname = `${label}.${DOMAIN}`;
155 let entry: DomainEntry | null;
156 try {
157 entry = await lookup(env, hostname);
158 } catch (error) {
159 console.error("could not read redirect", label, error);
160 return null;
161 }
162 if (!entry?.redirect || entry.redirect === hostname) return null;
163 return new Response(null, {
164 status: 301,
165 headers: {
166 location: redirectTo(request.url, entry.redirect),
167 "x-robots-tag": "noindex",
168 "cache-control": "public, max-age=3600",
169 },
170 });
171}
172
Agents and memory, checks and conflicts, profiles, slug renames, custom domains173/** A custom domain: its app, or a 308 to the hostname it is paired with. */
174async function custom(request: Request, env: Env, hostname: string): Promise<Response> {
175 let entry: DomainEntry | null;
176 try {
177 entry = await lookup(env, hostname);
178 } catch (error) {
179 console.error("could not read domain", hostname, error);
180 return page(503, "Try again in a moment", `<p><code>${escape(hostname)}</code> could not be looked up just now.</p>`, hostname);
181 }
182 if (!entry) {
183 return page(
184 404,
185 "This domain is not set up",
186 `<p><code>${escape(hostname)}</code> points at g1t, but no project serves it. Its owner adds it under the project's Settings, Deployments, on <a href="https://g1t.sh">g1t</a>.</p>`,
187 hostname,
188 );
189 }
190 if (entry.redirect && entry.redirect !== hostname) {
191 return new Response(null, {
192 status: 308,
193 headers: { location: redirectTo(request.url, entry.redirect), "cache-control": "public, max-age=300" },
194 });
195 }
196 return dispatch(env, request, entry.script, hostname, () =>
197 page(
198 404,
199 "Nothing deployed here yet",
200 `<p><code>${escape(hostname)}</code> serves a project's production, and it is not up. Deploying the project brings it here.</p>`,
201 hostname,
202 ),
203 );
204}
205
Projects live: fixes from walking them end to end206/** A branch's preview: `<project>-git-<branch>-<workspace>`. */
207function isPreview(label: string): boolean {
208 return label.includes("-git-");
209}
210
Deployments: a preview for every pull request, production on g1t.page211function missing(label: string): Response {
Projects live: fixes from walking them end to end212 const preview = isPreview(label);
Deployments: a preview for every pull request, production on g1t.page213 return page(
214 404,
215 preview ? "This preview is not up" : "Nothing deployed here",
216 preview
Projects live: fixes from walking them end to end217 ? `<p>A preview comes down when its pull request is closed or merged, or after its project's idle days without a visit. Pushing to the branch, or redeploying it from the project's Deployments page, brings it back.</p>`
218 : `<p>No app is deployed at <code>${escape(label)}.${DOMAIN}</code>. Deployments are turned on per project, from its Settings on g1t.</p>`,
Deployments: a preview for every pull request, production on g1t.page219 );
220}

This file's history is long; its oldest lines are credited to the oldest commit read.