| 1 | import { data } from "react-router"; |
| 2 | |
| 3 | import type { Route } from "./+types/ref"; |
| 4 | import { refCard } from "../../../lib/refs.server"; |
| 5 | import { requireUser, roleIn } from "../../../lib/session.server"; |
| 6 | |
| 7 | export 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 | */ |
| 16 | export 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 | } |