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.

32 linesCodeBlameRaw
1import { data } from "react-router";
2
3import type { Route } from "./+types/ref";
4import { refCard } from "../../../lib/refs.server";
5import { requireUser, roleIn } from "../../../lib/session.server";
6
7export type { RefCard } from "../../../lib/refs.server";
8
9/**
10 * `-/chat/ref?repo=<namespace>/<name>&number=<n>`, or with
11 * `workspace=<slug>` (this workspace when left out) instead of `repo`: the
12 * card that opens over an `owner/repo#12`, `acme#12` or `#12` chip in chat
13 * and in g1t's answers, read as lib/refs.ts says. Only what the viewer may read; anything
14 * else is not found. Kept a minute by the browser.
15 */
16export async function loader({ params, context, request }: Route.LoaderArgs) {
17 const viewer = requireUser(context, request);
18 if (!roleIn(viewer, params.owner)) throw data(null, { status: 404 });
19 const url = new URL(request.url);
20 const named = url.searchParams.get("repo") ?? "";
21 const [namespace, name] = named.split("/");
22 const number = Number(url.searchParams.get("number"));
23 const headers = { "cache-control": "private, max-age=60", vary: "Cookie" };
24 if (!Number.isInteger(number) || number < 1 || (named && (!namespace || !name))) {
25 return Response.json({ error: "not_found" }, { status: 404, headers });
26 }
27 const workspace = (url.searchParams.get("workspace") || params.owner).toLowerCase();
28 const scope = namespace && name ? { repo: { namespace: namespace.toLowerCase(), name } } : { workspace };
29 const card = await refCard(viewer, scope, number);
30 if (!card) return Response.json({ error: "not_found" }, { status: 404, headers });
31 return Response.json(card, { headers });
32}