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.
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 1 | import { redirect } from "react-router"; |
| 2 | ||
| Merge branch 'worktree-agent-a8385d293d42c913a' | 3 | import { isNamespaceShaped } from "@g1t/contracts"; |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 4 | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 5 | import type { Viewer } from "@g1t/contracts"; |
| 6 | ||
| 7 | import { identity, repos } from "./services.server"; | |
| Merge branch 'worktree-agent-a8385d293d42c913a' | 8 | import { underWorkspace } from "./workspace-nav"; |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 9 | |
| 10 | /** | |
| 11 | * A workspace that was renamed keeps its old address as a redirect for | |
| Merge branch 'worktree-agent-a8385d293d42c913a' | 12 | * `SLUG_HOLD_DAYS`, and an alias g1t's staff set (identity's aliases.rs: |
| 13 | * `g1t` for `flagon-io`) leads to its workspace for good. Call this where a | |
| 14 | * page is about to 404 on its first path segment: if `slug` is an old name | |
| 15 | * or an alias, it throws a 301 to the same page (path and query) under the | |
| 16 | * workspace's slug now. Otherwise it returns, and the caller 404s as | |
| 17 | * before. Only the not-found path pays for the lookup. | |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 18 | */ |
| 19 | export async function redirectIfRenamed(request: Request, slug: string): Promise<void> { | |
| 20 | const old = slug.toLowerCase(); | |
| Merge branch 'worktree-agent-a8385d293d42c913a' | 21 | // Nothing that could never have been a workspace's name or an alias is |
| 22 | // looked up. Reserved names such as `g1t` can be aliases. | |
| 23 | if (!isNamespaceShaped(old)) return; | |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 24 | let current: string | null = null; |
| 25 | try { | |
| 26 | current = await identity.resolveSlug(old); | |
| 27 | } catch { | |
| 28 | // A lookup that fails leaves the page a 404, never a 500. | |
| 29 | return; | |
| 30 | } | |
| 31 | if (!current || current === old) return; | |
| 32 | const url = new URL(request.url); | |
| Merge branch 'worktree-agent-a8385d293d42c913a' | 33 | throw redirect(underWorkspace(url.pathname, url.search, current), 301); |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 34 | } |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 35 | |
| 36 | /** | |
| 37 | * A repository transferred to another workspace keeps its old address as a | |
| 38 | * redirect until a repository is made there. Call this where a project page | |
| 39 | * is about to 404: if `owner/repo` is a path a repository left, and the | |
| 40 | * viewer may see it where it is now, it throws a 301 to the same page | |
| 41 | * there. A private repository's new address is never shown to someone who | |
| 42 | * cannot see it; they get the 404 as before. | |
| 43 | */ | |
| 44 | export async function redirectIfTransferred( | |
| 45 | request: Request, | |
| 46 | owner: string, | |
| 47 | repo: string, | |
| 48 | viewer: Viewer, | |
| 49 | ): Promise<void> { | |
| 50 | let now: { namespace: string; name: string } | null = null; | |
| 51 | try { | |
| 52 | now = await repos.resolvePath({ namespace: owner, name: repo }); | |
| 53 | if (!now || !(await repos.get(now, viewer)).ok) return; | |
| 54 | } catch { | |
| 55 | return; | |
| 56 | } | |
| 57 | const url = new URL(request.url); | |
| 58 | const segments = url.pathname.split("/"); | |
| 59 | segments[1] = now.namespace; | |
| 60 | segments[2] = now.name; | |
| 61 | throw redirect(segments.join("/") + url.search, 301); | |
| 62 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.