first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
# routes/build-routes
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<string, SearchIndex>; 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.