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.

54 linesCodeBlameRaw
1/**
2 * /sitemap.xml: the public pages, then the public projects Explore lists,
3 * newest first. Explore being unreachable leaves just the pages.
4 */
5import type { Route } from "./+types/sitemap-xml";
6import { search } from "../lib/services.server";
7
8/** Pages anyone can read, signed in or not. */
9const PAGES = [
10 "/",
11 "/pricing",
12 "/download",
13 "/explore",
14 "/support",
15 "/security",
16 "/policies",
17 ...["terms", "privacy", "acceptable-use", "refunds", "subprocessors"].map((policy) => `/policies/${policy}`),
18];
19
20/** How many of Explore's pages to list; each holds one page of projects. */
21const EXPLORE_PAGES = 10;
22
23function escape(text: string): string {
24 return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
25}
26
27export async function loader({ request }: Route.LoaderArgs) {
28 const site = new URL(request.url).origin;
29 const entries: { loc: string; lastmod?: string }[] = PAGES.map((path) => ({ loc: `${site}${path}` }));
30 for (let pageNumber = 1; pageNumber <= EXPLORE_PAGES; pageNumber++) {
31 const explore = await search.explore(null, { sort: "new", page: pageNumber }).catch(() => null);
32 if (!explore) break;
33 for (const repo of explore.repos) {
34 const lastmod = (repo.pushedAt ?? repo.createdAt)?.slice(0, 10);
35 entries.push({ loc: `${site}/${repo.namespace}/${repo.name}`, lastmod });
36 }
37 if (!explore.more) break;
38 }
39 const body = [
40 '<?xml version="1.0" encoding="UTF-8"?>',
41 '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
42 ...entries.map(
43 (entry) => ` <url><loc>${escape(entry.loc)}</loc>${entry.lastmod ? `<lastmod>${entry.lastmod}</lastmod>` : ""}</url>`,
44 ),
45 "</urlset>",
46 "",
47 ].join("\n");
48 return new Response(body, {
49 headers: {
50 "content-type": "application/xml; charset=utf-8",
51 "cache-control": "public, max-age=3600",
52 },
53 });
54}