Skip to content

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

36 linesCodeBlameRaw
1/**
2 * `/<owner>/<repo>/ref/<number>`: the card that opens over a `#12` in a
3 * commit message or on a timeline (components/commit-message.tsx), for
4 * anyone who may read the repository, signed in or not. Issues and pull
5 * requests share numbers: the issue if there is one, else the pull
6 * request; anything the viewer may not read is not found. Kept a minute
7 * by the browser, and out of indexes (lib/robots.ts).
8 */
9import type { Route } from "./+types/ref-card";
10import type { RefCard } from "../workspace/chat/ref";
11import { work } from "../../lib/services.server";
12import { getViewer } from "../../lib/session.server";
13
14const HEADERS = {
15 "cache-control": "private, max-age=60",
16 vary: "Cookie",
17 "x-robots-tag": "noindex, nofollow",
18};
19
20export async function loader({ params, context }: Route.LoaderArgs) {
21 const viewer = getViewer(context);
22 const repo = { namespace: params.owner.toLowerCase(), name: params.repo };
23 const number = Number(params.number);
24 if (!Number.isInteger(number) || number < 1) return Response.json({ error: "not_found" }, { status: 404, headers: HEADERS });
25 const slug = `${repo.namespace}/${repo.name}`;
26 const issue = await work.getIssue(repo, number, viewer).catch(() => null);
27 let card: RefCard | null = issue?.ok
28 ? { kind: "issue", repo: slug, number, title: issue.value.issue.title, state: String(issue.value.issue.state) }
29 : null;
30 if (!card) {
31 const pull = await work.getPull(repo, number, viewer).catch(() => null);
32 if (pull?.ok) card = { kind: "pull", repo: slug, number, title: pull.value.pull.title, state: pull.value.pull.status };
33 }
34 if (!card) return Response.json({ error: "not_found" }, { status: 404, headers: HEADERS });
35 return Response.json(card, { headers: HEADERS });
36}