# routes/build-routes _(no submodules)_ ## Purpose The build-routes module constructs the `OpenAPIHono` instance that the plugin mounts under `routePrefix` (`/search` by default). It declares the 9 canonical search endpoints — query, suggest, list indexes, create index, get index, delete index, index document, bulk index, and remove document — wiring every request through Zod validation via `@hono/zod-openapi`, dispatching to the in-memory engine in `service/service.ts`, and propagating typed events through the supplied `emitEvent` callback. Error responses are normalised to the canonical `{ error: string }` shape and the HTTP status is driven by the `context.statusCode` carried on each `SearchError`. ## Features - 9 endpoints with OpenAPI 3.1 metadata baked in: every request body / path param / query string is Zod-validated, every response shape declared. - Typed `SearchRouteEvent` discriminated union so emissions never need `as any` and consumers can pattern-match on `event.type`. - Typed errors mapped to HTTP via `errorPayload`: `SearchError` with `context.statusCode === 404` maps to 404, every other failure to 400; non-`SearchError` throwables stringify their message. - Side-effect-free factory — `createSearchRoutes` builds a fresh router on every call, so concurrent plugin instantiations never share router state. - Pure dispatch layer — the routes carry zero business logic; they exist purely to translate HTTP into service calls and back. ## Usage: Basic ```ts import { createSearchRoutes } from "@suaveplan/api-plugin-search"; const router = createSearchRoutes({ indexes, serviceConfig: { maxIndexes: 100, maxDocumentsPerIndex: 100_000, defaultAnalyzer: "standard", }, }); app.route("/search", router); ``` ## Usage: Advanced Wire the emitter to the host event bus so domain code can react to search lifecycle: ```ts const router = createSearchRoutes({ indexes, serviceConfig, emitEvent: (event) => { eventBus.emit(event.type, event.payload); logger.info("search-event", { type: event.type }); }, }); ``` ## API Reference ### `createSearchRoutes(deps): OpenAPIHono` Returns the configured router with 9 endpoints registered. ### `SearchRoutesDeps` `{ indexes: Map; serviceConfig: SearchServiceConfig; emitEvent?: (event: SearchRouteEvent) => void }`. ### `SearchRouteEvent` Discriminated union — `search:query:executed` / `search:index:updated` / `search:index:created` / `search:index:deleted`. Every variant carries `type` + `payload` so emitters can pattern-match without unsafe casts. ## Implementation Notes The error-handling helper `errorPayload` exists once rather than per route so the mapping rule (`statusCode 404 → 404`, anything else → 400) lives in one place. The five lookup routes that throw 404 by contract clamp the payload status to 404 explicitly; the index/bulk write routes that can throw `INDEX_NOT_FOUND` (404) or `DOCUMENT_LIMIT_REACHED` (400) consult the underlying status. The `getSearchIndex` post-create check guards against the impossible case where the service inserted a name that immediately fails lookup — defensive but unreachable, kept to satisfy the `info!` exclamation that upstream relied on.