# schemas/schemas _(no submodules)_ ## Purpose The schemas module owns the public Zod surface of `@suaveplan/api-plugin-search`. Every HTTP route in the package validates its request body, path params, or query string against one of these schemas before invoking the service layer, and every response shape is declared here so `@hono/zod-openapi` can publish a typed `/openapi.json` document without per-route duplication. Inferred types are exported in parallel so direct programmatic consumers (e.g. another plugin building on top of the search service) can construct payloads with full type safety. ## Features - Thirteen schemas covering the full upstream search surface — queries, hits, facets, sort orders, index status enums, index field declarations, document indexing, bulk indexing, suggest queries, and every response shape. - Two const-object enums (`SearchSortOrder`, `IndexStatus`) so consumers can branch on string literals without re-typing them. - Sensible defaults at the boundary (`sort: "relevance"`, `limit: 20`, `offset: 0`, `highlight: false`, `highlightTag: "mark"`, `analyzer: "standard"`, `weight: 1`, `facet: false`) so consumers only pass the fields they care about. - Hard upper bounds on every numeric and string field — `query` capped at 1000 chars, index names at 128 chars, `limit` ≤ 200, bulk docs ≤ 1000 — keeping the HTTP surface within sane resource budgets. - Inferred TypeScript types exported alongside each schema so call sites can type-check payloads at compile time without `z.infer` boilerplate. ## Usage: Basic ```ts import { SearchQuerySchema, type SearchQuery, } from "@suaveplan/api-plugin-search"; const parsed = SearchQuerySchema.safeParse({ query: "hello world", index: "posts", }); if (parsed.success) { const q: SearchQuery = parsed.data; // q.sort === "relevance" by default, q.limit === 20, ... } ``` ## Usage: Advanced Compose the schemas with `@hono/zod-openapi` to publish typed routes: ```ts import { createRoute } from "@hono/zod-openapi"; import { SearchQuerySchema, SearchResultSchema, } from "@suaveplan/api-plugin-search"; export const searchRoute = createRoute({ method: "post", path: "/query", request: { body: { content: { "application/json": { schema: SearchQuerySchema } }, }, }, responses: { 200: { description: "Search results", content: { "application/json": { schema: SearchResultSchema } }, }, }, }); ``` ## API Reference | Symbol | Shape | |---|---| | `SearchSortOrder` | const object + type union — `"relevance"`, `"date_asc"`, `"date_desc"`, `"alpha_asc"`, `"alpha_desc"` | | `IndexStatus` | const object + type union — `"active"`, `"building"`, `"error"` | | `SearchQuerySchema` / `SearchQuery` | request body for `POST /query` | | `SearchHitSchema` / `SearchHit` | one hit returned by `search()` | | `FacetValueSchema` / `FacetValue` | `{ value, count }` | | `FacetSchema` / `Facet` | `{ field, values: FacetValue[] }` | | `SearchResultSchema` / `SearchResult` | response shape of `POST /query` | | `IndexFieldSchema` / `IndexField` | per-field config in `CreateIndex` | | `CreateIndexSchema` / `CreateIndex` | request body for `POST /indexes` | | `IndexInfoSchema` / `IndexInfo` | response shape of `GET /indexes/:name` | | `IndexListQuerySchema` / `IndexListQuery` | query string for `GET /indexes` | | `IndexDocumentSchema` / `IndexDocument` | request body for indexing | | `BulkIndexSchema` / `BulkIndex` | request body for bulk indexing | | `SuggestQuerySchema` / `SuggestQuery` | request body for `POST /suggest` | | `SuggestionSchema` / `Suggestion` | one entry in `SuggestResult.suggestions` | | `SuggestResultSchema` / `SuggestResult` | response shape of `POST /suggest` | ## Implementation Notes All numeric fields use `z.coerce.number()` so query-string values (`"20"`) parse correctly. `z.record(z.string(), z.unknown())` is used for free-form document fields and filter maps. The `createdAt` field on `IndexInfoSchema` accepts both ISO-string and `Date` so the schema can validate both the service-internal shape and the serialized-over-HTTP shape.