# `routes` _(no submodules)_ ## Purpose Builds the five OpenAPI route entries `createTenantPlugin` mounts when a `TenantStore` is configured: `GET /`, `POST /`, `GET /:id`, `PATCH /:id`, and `DELETE /:id`, each paired with a Hono handler that delegates to the `TenantService`. Every body, query, and response shape flows through the Zod schemas from `schemas/routes.ts` so the unified OpenAPI 3.1 document the host serves stays in lock-step with the runtime behaviour. ## Features - Five-route CRUD surface returned as `PluginRouteEntry[]` ready for `definePluginRoutes`. - Per-handler Zod validation — bodies, query parameters, and path params are validated explicitly with `safeParse` so the error shape is consistent across all five handlers. - Domain → wire projection via `toResponse` so `Date` fields serialise as ISO strings and optional `plan` / `metadata` keys are omitted rather than serialised as `null`. - `TenantPluginError` instances are translated to JSON `{ success: false, error: { code, message } }` with the carried `statusCode` so callers see 404 / 409 / 500 as appropriate. - Soft-delete success response is `{ success: true }`. ## Usage: Basic Example ```ts import { buildTenantRoutes, createTenantService, MemoryTenantStore } from "@suaveplan/api-plugin-tenant"; import { headerResolver } from "@suaveplan/api-tenant"; const store = new MemoryTenantStore(); const resolver = headerResolver("x-tenant-id", (id) => store.getById(id)); const service = createTenantService({ resolver, store }); const entries = buildTenantRoutes(service); console.log(entries.length); // 5 ``` ## Usage: Advanced Example ```ts import { buildTenantRoutes, createTenantService, MemoryTenantStore } from "@suaveplan/api-plugin-tenant"; import { headerResolver } from "@suaveplan/api-tenant"; import { definePluginRoutes, createOpenAPIRegistry } from "@suaveplan/api-openapi"; import { OpenAPIHono } from "@hono/zod-openapi"; const store = new MemoryTenantStore(); const resolver = headerResolver("x-tenant-id", (id) => store.getById(id)); const service = createTenantService({ resolver, store }); const app = new OpenAPIHono(); const registry = createOpenAPIRegistry({ info: { title: "demo", version: "0.0.1" } }); const entries = buildTenantRoutes(service); // Caller is responsible for prefixing the paths and applying any RBAC middleware. const prefixed = entries.map((e) => ({ ...e, route: { ...e.route, path: `/tenants${e.route.path === "/" ? "" : e.route.path}` }, })); definePluginRoutes(prefixed, { app, registry, pluginName: "tenant" }); ``` ## API Reference - `function buildTenantRoutes(service: TenantService): PluginRouteEntry[]` — returns five entries. Path templates use `/{id}` for the resource routes (OpenAPI style), which Hono accepts via the `app.openapi(route, handler)` integration in `definePluginRoutes`. ## Implementation Notes The handlers validate inputs even though `definePluginRoutes` already wires `c.req.valid(...)` because we want the same handlers to be runnable on a Hono-only mount (no OpenAPI registry) without losing boundary validation. Errors are JSON-formatted with explicit status codes so consumers using a thin error handler do not need to know plugin-internal error shapes. The list response shape (`{ items, total }`) is deliberately minimal; consumers needing cursor-based pagination wire their own variant or subclass the schema.