import { Document } from "flexsearch"; import { buildResult, RESULT_POOL } from "./types.ts"; import type { IndexedDocument, SearchFn } from "./types.ts"; /** * The fields FlexSearch indexes. An anonymous alias of the indexed fields: * unlike the `IndexedDocument` interface it satisfies FlexSearch's * index-signature `DocumentData` constraint structurally. */ type SearchDocument = Pick< IndexedDocument, "content" | "description" | "route" | "title" >; /** * FlexSearch: reuse the same static `blume-search.json` Orama ships, but build * a FlexSearch document index in the browser. Keyless; works in dev and build. * Matched routes are resolved back to their full documents (so we never depend * on `enrich` typing) and shaped by the shared `buildResult` helper. */ export const createSearch = async (opts: { indexUrl: string; }): Promise => { const response = await fetch(opts.indexUrl); // SAFETY: `blume-search.json` is generated by our own search indexer, which // writes exactly this document shape. const documents = (await response.json()) as IndexedDocument[]; const byRoute = new Map(documents.map((doc) => [doc.route, doc])); const index = new Document({ document: { id: "route", index: ["title", "description", "content"] }, tokenize: "forward", }); for (const doc of documents) { index.add(doc); } // FlexSearch's in-memory search is synchronous, so the SearchFn resolves // immediately rather than awaiting anything. return (query, options) => { const groups = index.search(query, { limit: RESULT_POOL }); const matched: IndexedDocument[] = []; const seen = new Set(); for (const group of groups) { for (const id of group.result) { const route = String(id); if (seen.has(route)) { continue; } seen.add(route); const doc = byRoute.get(route); // Filter to the active locale and version (when requested) before // shaping, so section counts and results stay within scope. `""` is // the current version, so version presence is tested explicitly. if ( doc && (!options?.locale || doc.locale === options.locale) && (options?.version === undefined || (doc.version ?? "") === options.version) ) { matched.push(doc); } } } return Promise.resolve(buildResult(matched, query, options?.section)); }; };