g1t/apps/web/app/lib/branch-redirect.server.ts

36 lines1,303 bytesCodeBlame
1import { redirect } from "react-router";
2
3import type { RepoPath, Viewer } from "@g1t/contracts";
4
5import { renamedBranchPath } from "./repo-lifecycle";
6import { repos } from "./services.server";
7
8/**
9 * A renamed branch keeps its old name as a redirect. Call this where a
10 * tree or blob page is about to 404 on `ref`: if the branch was renamed
11 * away from it, it throws a 301 to the same page on the new name.
12 * Otherwise it returns, and the caller 404s as before. Only the not-found
13 * path pays for the lookup.
14 */
15export async function redirectIfBranchRenamed(
16 request: Request,
17 path: RepoPath,
18 viewer: Viewer,
19 ref: string,
20): Promise<void> {
21 let to: string | null = null;
22 try {
23 const repo = await repos.get(path, viewer);
24 if (!repo.ok) return;
25 // `HEAD` is the default branch, as git means it (Go's go-source links use it).
26 const now = ref === "HEAD" ? repo.value.defaultBranch : await repos.resolveBranch(repo.value.id, ref);
27 if (!now || now === ref) return;
28 const url = new URL(request.url);
29 to = renamedBranchPath(url.pathname, url.search, now);
30 } catch {
31 // A lookup that fails leaves the page a 404, never a 500.
32 return;
33 }
34 // A rename is for good; what HEAD names can change.
35 if (to) throw redirect(to, ref === "HEAD" ? 302 : 301);
36}