Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,25 @@ import {
DOCS_FILE_EXTENSIONS,
} from "../lib/content.server";
import { BASE_URL } from "../lib/constants";
import { getAllApiReferenceSitemapEntries } from "../lib/sitemapEntries";

export default function sitemap(): MetadataRoute.Sitemap {
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const filePaths = getAllFilesInDir(CONTENT_DIR, [], DOCS_FILE_EXTENSIONS);

const pages = filePaths.map((path) => {
const slug = path.replace(CONTENT_DIR, "").replace(/\.mdx?$/, "");
const pages = filePaths
.filter((path) => !path.includes("/__"))
.map((path) => {
const slug = path.replace(CONTENT_DIR, "").replace(/\.mdx?$/, "");

return {
url: `${BASE_URL}/${slug}`,
lastModified: new Date(),
priority: 1,
changeFrequency: "daily",
};
});
return {
url: `${BASE_URL}/${slug}`,
lastModified: new Date(),
priority: 1,
changeFrequency: "daily" as const,
};
});

const apiReferencePages = await getAllApiReferenceSitemapEntries();

return [
{
Expand All @@ -28,5 +33,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
priority: 1,
changeFrequency: "daily",
},
].concat(pages) as MetadataRoute.Sitemap;
...pages,
...apiReferencePages,
];
}
92 changes: 92 additions & 0 deletions lib/sitemapEntries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { MetadataRoute } from "next";

import {
API_REFERENCE_OVERVIEW_CONTENT,
} from "@/data/sidebars/apiOverviewSidebar";
import {
MAPI_REFERENCE_OVERVIEW_CONTENT,
} from "@/data/sidebars/mapiOverviewSidebar";
import { BASE_URL } from "./constants";
import {
ApiReferencePath,
getAllApiReferencePaths,
SpecName,
} from "./openApiSpec";

type SitemapEntry = MetadataRoute.Sitemap[number];

function createSitemapEntry(path: string): SitemapEntry {
return {
url: `${BASE_URL}${path}`,
lastModified: new Date(),
priority: 1,
changeFrequency: "daily",
};
}

function apiReferencePathToUrl(
basePath: string,
apiPath: ApiReferencePath,
): string {
const { resource, slug } = apiPath.params;

if (!slug || slug.length === 0) {
return `${basePath}/${resource}`;
}

return `${basePath}/${resource}/${slug.join("/")}`;
}

function getOverviewPaths(
basePath: string,
overviewPages: { slug: string }[],
): string[] {
const paths = new Set<string>([basePath, `${basePath}/overview`]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sitemap includes redirecting base paths

Medium Severity

getOverviewPaths always adds the API and Management API base paths to the sitemap, but those routes redirect to their /overview counterparts in next.config.js. Search engines then hit redirecting URLs instead of the canonical overview pages this PR is trying to expose.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 45e8cdd. Configure here.


for (const page of overviewPages) {
if (page.slug === "/") {
continue;
}

paths.add(`${basePath}/overview${page.slug}`);
}

return Array.from(paths);
}

async function getApiReferenceSitemapEntries(
specName: SpecName,
): Promise<SitemapEntry[]> {
const basePath = specName === "api" ? "/api-reference" : "/mapi-reference";
const overviewContent =
specName === "api"
? API_REFERENCE_OVERVIEW_CONTENT
: MAPI_REFERENCE_OVERVIEW_CONTENT;
const overviewPages = overviewContent[0]?.pages ?? [];
const paths = new Set<string>(getOverviewPaths(basePath, overviewPages));
const apiPaths = await getAllApiReferencePaths(specName);

for (const apiPath of apiPaths) {
paths.add(apiReferencePathToUrl(basePath, apiPath));
}

return Array.from(paths)
.sort()
.map(createSitemapEntry);
}

async function getAllApiReferenceSitemapEntries(): Promise<SitemapEntry[]> {
const [apiEntries, mapiEntries] = await Promise.all([
getApiReferenceSitemapEntries("api"),
getApiReferenceSitemapEntries("mapi"),
]);

return [...apiEntries, ...mapiEntries];
}

export {
apiReferencePathToUrl,
createSitemapEntry,
getAllApiReferenceSitemapEntries,
getApiReferenceSitemapEntries,
};
Loading