Skip to content
Merged
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
55 changes: 46 additions & 9 deletions apps/docs/app/api/search/route.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
import { createFromSource } from "fumadocs-core/search/server";
import { structure } from "fumadocs-core/mdx-plugins";
import {
type AdvancedIndex,
createSearchAPI,
} from "fumadocs-core/search/server";
import remarkMdx from "remark-mdx";
import type { AsyncPageData } from "@/app/docs/[[...slug]]/page";
import { source } from "@/lib/source";

export const dynamic = "force-dynamic";

// Lazy initialization to avoid build-time errors with async source
let searchHandler: ReturnType<typeof createFromSource> | null = null;
let searchApi: ReturnType<typeof createSearchAPI<"advanced">> | null = null;

function getSearchHandler() {
if (!searchHandler) {
searchHandler = createFromSource(source);
async function buildIndexes(): Promise<AdvancedIndex[]> {
const pages = source.getPages();

const results = await Promise.all(
pages.map(async (page): Promise<AdvancedIndex | null> => {
try {
const pageData = page.data as AsyncPageData;
if (!pageData.getText) {
return null;
}

const processed = await pageData.getText("processed");

return {
id: page.url,
title: pageData.title ?? "",
description: pageData.description ?? "",
url: page.url,
structuredData: structure(processed, [remarkMdx]),
};
} catch {
console.error(`Failed to index page: ${page.url}`);
return null;
}
}),
);

return results.filter((index): index is AdvancedIndex => index !== null);
}

async function getSearchAPI() {
if (!searchApi) {
const indexes = await buildIndexes();
searchApi = createSearchAPI("advanced", { indexes });
}
return searchHandler;
return searchApi;
}

export function GET(request: Request) {
const handler = getSearchHandler();
return handler.GET(request);
export async function GET(request: Request) {
const api = await getSearchAPI();
return api.GET(request);
}
2 changes: 1 addition & 1 deletion apps/docs/app/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { onRateDocs } from "@/lib/feedback-action";
import { getPageImage, source } from "@/lib/source";
import { getMDXComponents } from "@/mdx-components";

type AsyncPageData = DocMethods & {
export type AsyncPageData = DocMethods & {
title?: string;
description?: string;
load: () => Promise<DocData>;
Expand Down
3 changes: 3 additions & 0 deletions apps/docs/source.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export const docs = defineDocs({
docs: {
schema: frontmatterSchema,
async: true,
postprocess: {
includeProcessedMarkdown: true,
},
},
meta: {
schema: metaSchema,
Expand Down
Loading