Compare changes
Choose two branches to see what one has that the other does not, then open a pull request for it.
1 commit
6 files+46−190/6 viewed
| 646 | 646 | const words: Record<string, string> = { | |
| 647 | 647 | settings: "Account", | |
| 648 | 648 | explore: "Explore", | |
| 649 | − | new: "New repository", | |
| 649 | + | new: "New project", | |
| 650 | 650 | search: "Search", | |
| 651 | 651 | workspaces: "New workspace", | |
| 652 | 652 | }; |
| 169 | 169 | <> | |
| 170 | 170 | <Link | |
| 171 | 171 | to="/new" | |
| 172 | − | aria-label="New repository" | |
| 172 | + | aria-label="New project" | |
| 173 | 173 | className="rounded-md border border-line p-1.5 text-muted transition-colors hover:border-line-strong hover:text-fg" | |
| 174 | 174 | > | |
| 175 | 175 | <Plus size={16} /> | |
| 214 | 214 | <DropdownMenuItem asChild> | |
| 215 | 215 | <Link to="/new"> | |
| 216 | 216 | <Plus /> | |
| 217 | − | New repository | |
| 217 | + | New project | |
| 218 | 218 | </Link> | |
| 219 | 219 | </DropdownMenuItem> | |
| 220 | 220 | <DropdownMenuSeparator /> |
| 80 | 80 | {role && ( | |
| 81 | 81 | <ButtonLink to={`/new?workspace=${workspace.slug}`}> | |
| 82 | 82 | <Plus size={15} /> | |
| 83 | − | New repository | |
| 83 | + | New project | |
| 84 | 84 | </ButtonLink> | |
| 85 | 85 | )} | |
| 86 | 86 | </div> |
| 482 | 482 | /// and its running app get. | |
| 483 | 483 | pub async fn resolve_settings(&self, a: ResolveSettingsArgs) -> Result<ResolvedSettings> { | |
| 484 | 484 | let environment = a.environment.as_deref(); | |
| 485 | − | let (project_id, slug) = match (a.project_id, a.project_slug) { | |
| 486 | − | (Some(id), Some(slug)) => (id, slug), | |
| 487 | − | _ => match self.project_of(&a.repo_id).await? { | |
| 488 | − | Some(project) => (project.id, project.slug), | |
| 489 | − | None => return Ok(ResolvedSettings::default()), | |
| 490 | − | }, | |
| 485 | + | // Rows kept under the repository from before projects move to its | |
| 486 | + | // primary project first, however the project is named here. | |
| 487 | + | let primary = self.project_of(&a.repo_id).await?; | |
| 488 | + | let (project_id, slug) = match (a.project_id, a.project_slug, primary) { | |
| 489 | + | (Some(id), Some(slug), _) => (id, slug), | |
| 490 | + | (_, _, Some(project)) => (project.id, project.slug), | |
| 491 | + | _ => return Ok(ResolvedSettings::default()), | |
| 491 | 492 | }; | |
| 492 | 493 | Ok(ResolvedSettings { | |
| 493 | 494 | secrets: self |
| 33 | 33 | /** Serves the site's files, for an app that brings no code of its own. */ | |
| 34 | 34 | const ASSETS_ONLY = `export default { fetch(request, env) { return env.ASSETS.fetch(request); } };\n`; | |
| 35 | 35 | ||
| 36 | − | const HTML_HANDLING = ["auto-trailing-slash", "force-trailing-slash", "drop-trailing-slash", "none"]; | |
| 36 | + | /** What an app answers between being taken down and being gone. */ | |
| 37 | + | const TAKEN_DOWN = `export default { | |
| 38 | + | fetch() { | |
| 39 | + | return new Response("<!doctype html><meta charset=utf-8><meta name=robots content=noindex><title>Not up</title><body style='font:16px system-ui;background:#121214;color:#ececf1;display:grid;place-items:center;min-height:100vh;margin:0'><main><h1>This app is not up</h1><p style='color:#9a9aa6'>It was taken down. Deploying it again brings it back.</p></main>", { status: 404, headers: { "content-type": "text/html; charset=utf-8", "x-robots-tag": "noindex", "cache-control": "no-store" } }); | |
| 40 | + | }, | |
| 41 | + | }; | |
| 42 | + | `; | |
| 43 | + | ||
| 44 | + | const HTML_HANDLING =["auto-trailing-slash", "force-trailing-slash", "drop-trailing-slash", "none"]; | |
| 37 | 45 | const NOT_FOUND_HANDLING = ["single-page-application", "404-page", "none"]; | |
| 38 | 46 | ||
| 39 | 47 | export class Cloudflare { | |
| 148 | 156 | ); | |
| 149 | 157 | } | |
| 150 | 158 | ||
| 151 | − | /** Takes an app down. Already gone is fine. */ | |
| 159 | + | /** | |
| 160 | + | * Takes an app down. Already gone is fine. | |
| 161 | + | * | |
| 162 | + | * A deleted app can keep answering for a while where Cloudflare still has | |
| 163 | + | * it warm. So it is first replaced by a notice that it is down, which | |
| 164 | + | * reaches the edge as fast as any deploy, and deleted after. | |
| 165 | + | */ | |
| 152 | 166 | async deleteScript(script: string): Promise<void> { | |
| 167 | + | const form = new FormData(); | |
| 168 | + | form.append( | |
| 169 | + | "metadata", | |
| 170 | + | JSON.stringify({ main_module: "index.js", compatibility_date: "2026-09-26", bindings: [], tags: ["taken-down"] }), | |
| 171 | + | ); | |
| 172 | + | form.append("index.js", new File([TAKEN_DOWN], "index.js", { type: "application/javascript+module" })); | |
| 173 | + | await this.call("PUT", this.scriptPath(script), form).catch(() => undefined); | |
| 153 | 174 | try { | |
| 154 | 175 | await this.call("DELETE", `${this.scriptPath(script)}?force=true`); | |
| 155 | 176 | } catch (error) { |
| 2 | 2 | * The dispatcher for g1t.page: every app deployed by g1t is served here. | |
| 3 | 3 | * | |
| 4 | 4 | * The hostname's first label is the app's script name in the Workers for | |
| 5 | − | * Platforms namespace (`pr-12--web--acme.g1t.page` is pull request 12's | |
| 6 | − | * preview of acme/web), so a request needs no lookup: the app is fetched | |
| 7 | − | * by name and runs only for as long as it answers. An app no one visits | |
| 5 | + | * Platforms namespace (`web-git-fix-login-acme.g1t.page` is the fix-login | |
| 6 | + | * branch's preview of acme's web project), so a request needs no lookup: | |
| 7 | + | * the app is fetched by name and runs only for as long as it answers. An app no one visits | |
| 8 | 8 | * runs nothing and costs nothing. | |
| 9 | 9 | * | |
| 10 | 10 | * Kept apart from g1t.sh, so apps share no cookies or origin with the site | |
| 81 | 81 | ); | |
| 82 | 82 | } | |
| 83 | 83 | // Previews are for the people reviewing a change, not search engines. | |
| 84 | − | if (label.startsWith("pr-")) { | |
| 84 | + | if (isPreview(label)) { | |
| 85 | 85 | response = new Response(response.body, response); | |
| 86 | 86 | response.headers.set("x-robots-tag", "noindex"); | |
| 87 | 87 | } | |
| 89 | 89 | }, | |
| 90 | 90 | } satisfies ExportedHandler<Env>; | |
| 91 | 91 | ||
| 92 | + | /** A branch's preview: `<project>-git-<branch>-<workspace>`. */ | |
| 93 | + | function isPreview(label: string): boolean { | |
| 94 | + | return label.includes("-git-"); | |
| 95 | + | } | |
| 96 | + | ||
| 92 | 97 | function missing(label: string): Response { | |
| 93 | − | const preview = label.startsWith("pr-"); | |
| 98 | + | const preview = isPreview(label); | |
| 94 | 99 | return page( | |
| 95 | 100 | 404, | |
| 96 | 101 | preview ? "This preview is not up" : "Nothing deployed here", | |
| 97 | 102 | preview | |
| 98 | − | ? `<p>A preview comes down when its pull request is closed or merged, or after its repository's idle days without a visit. Pushing to the pull request, or redeploying it from the repository's Deployments page, brings it back.</p>` | |
| 99 | − | : `<p>No app is deployed at <code>${escape(label)}.${DOMAIN}</code>. Deployments are turned on per repository, from its Deployments page on g1t.</p>`, | |
| 103 | + | ? `<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>` | |
| 104 | + | : `<p>No app is deployed at <code>${escape(label)}.${DOMAIN}</code>. Deployments are turned on per project, from its Settings on g1t.</p>`, | |
| 100 | 105 | ); | |
| 101 | 106 | } |