From ebc8175337b1a21f9d52e192e224a5f7d3a0e283 Mon Sep 17 00:00:00 2001 From: Teal Larson Date: Thu, 14 May 2026 13:54:11 -0400 Subject: [PATCH 1/2] fix(sitemap): include statically-generated toolkit pages Toolkit pages at /en/resources/integrations/{category}/{toolkitId} were excluded from the sitemap because the filesystem walk skips directories whose names contain "[". This means search engines had no direct signal to crawl them. Uses the existing listToolkitRoutes() helper to append toolkit URLs after the MDX walk, deduplicates across both sources, and excludes the "others" category which has no on-disk route. Co-Authored-By: Claude Sonnet 4.6 --- app/sitemap.ts | 31 ++++++++++++++++++++++++++----- tests/sitemap.test.ts | 14 +++++++++++++- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/app/sitemap.ts b/app/sitemap.ts index 45b6615cf..7a908a3b0 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -1,6 +1,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import type { MetadataRoute } from "next"; +import { listToolkitRoutes } from "./_lib/toolkit-static-params"; const SITE_URL = process.env.SITE_URL ?? "https://docs.arcade.dev"; const NORMALIZED_SITE_URL = SITE_URL.replace(/\/+$/, ""); @@ -43,13 +44,33 @@ async function collectRoutes(dir: string): Promise { return entries; } +async function buildSitemap(): Promise { + const [mdxRoutes, toolkitRoutes] = await Promise.all([ + collectRoutes(APP_DIR), + listToolkitRoutes(), + ]); + + const toolkitEntries: MetadataRoute.Sitemap = toolkitRoutes + .filter((route) => route.category !== "others") + .map((route) => ({ + url: `${NORMALIZED_SITE_URL}/en/resources/integrations/${route.category}/${route.toolkitId}`, + })); + + const seen = new Set(mdxRoutes.map((r) => r.url)); + const uniqueToolkitEntries = toolkitEntries.filter((entry) => { + if (seen.has(entry.url)) return false; + seen.add(entry.url); + return true; + }); + + return [...mdxRoutes, ...uniqueToolkitEntries].sort((a, b) => + a.url.localeCompare(b.url) + ); +} + export default function sitemap(): Promise { if (!cachedRoutes) { - cachedRoutes = collectRoutes(APP_DIR).then((routes) => { - routes.sort((a, b) => a.url.localeCompare(b.url)); - return routes; - }); + cachedRoutes = buildSitemap(); } - return cachedRoutes; } diff --git a/tests/sitemap.test.ts b/tests/sitemap.test.ts index 1bd5a556b..3ceb0bb75 100644 --- a/tests/sitemap.test.ts +++ b/tests/sitemap.test.ts @@ -19,9 +19,21 @@ test("sitemap lists expected URLs", async () => { true ); - // Known page should be present + // Known static page should be present expect(urls).toContain("https://example.test/en/references/changelog"); + // Toolkit pages should be included + expect(urls).toContain( + "https://example.test/en/resources/integrations/development/github" + ); + const integrationUrls = urls.filter((url) => + url.includes("/en/resources/integrations/") + ); + expect(integrationUrls.length).toBeGreaterThan(10); + + // No dynamic-segment placeholders should leak into output + expect(urls.every((url) => !url.includes("["))).toBe(true); + // No duplicates const duplicates = urls.filter( (url, index, arr) => arr.indexOf(url) !== index From 7d4f29375ca8d433470ceda94b80b42ea2509307 Mon Sep 17 00:00:00 2001 From: Teal Larson Date: Thu, 14 May 2026 14:09:29 -0400 Subject: [PATCH 2/2] fix(sitemap): wrap if statement in block per linter Co-Authored-By: Claude Sonnet 4.6 --- app/sitemap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/sitemap.ts b/app/sitemap.ts index 7a908a3b0..2677eea14 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -58,7 +58,7 @@ async function buildSitemap(): Promise { const seen = new Set(mdxRoutes.map((r) => r.url)); const uniqueToolkitEntries = toolkitEntries.filter((entry) => { - if (seen.has(entry.url)) return false; + if (seen.has(entry.url)) { return false; } seen.add(entry.url); return true; });