| 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 | */ |
| 9 | import type { Route } from "./+types/ref-card"; |
| 10 | import type { RefCard } from "../workspace/chat/ref"; |
| 11 | import { work } from "../../lib/services.server"; |
| 12 | import { getViewer } from "../../lib/session.server"; |
| 13 | |
| 14 | const HEADERS = { |
| 15 | "cache-control": "private, max-age=60", |
| 16 | vary: "Cookie", |
| 17 | "x-robots-tag": "noindex, nofollow", |
| 18 | }; |
| 19 | |
| 20 | export 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 | } |