# `routes/build-routes` — auth-gated import routes ## Purpose Constructs the `OpenAPIHono` router mounted by `createImportPlugin` at the configured `routePrefix`. Five routes are registered — `POST /preview`, `POST /`, `GET /`, `GET /{id}`, `DELETE /{id}` — each gated behind `requireAuth()` from `@suaveplan/api-plugin-auth` so anonymous requests return 401 problem+json before they ever reach a handler. Owner-scoped routes read `c.get("user").id` and pass it through to the canonical `ImportService`, which raises `IMPORT.NOT_FOUND` (mapped to 404 problem+json) on foreign-owner lookups so the surface is anti-enumeration-safe. ## Features - Five OpenAPI routes with full Zod request / response schemas. - Per-route `app.use("/*", requireAuth())` guard. - `progressToResponse()` shape mapper so the response body always satisfies `ImportJobResponseSchema`. - Every handler funnels error paths through `respondProblemJson` so the response shape is uniform across success and failure. ## Usage: Basic Example ```ts import { createImportRoutes, ImportService } from "@suaveplan/api-plugin-import"; import { OpenAPIHono } from "@hono/zod-openapi"; const service = new ImportService(); const app = new OpenAPIHono(); app.route("/imports", createImportRoutes({ service })); ``` ## Usage: Advanced Example ```ts import { createImportRoutes, ImportService, MemoryImportStore } from "@suaveplan/api-plugin-import"; import { OpenAPIHono } from "@hono/zod-openapi"; const store = new MemoryImportStore(); const service = new ImportService({ store }); service.bus.on("import.progress", (snap) => sse.broadcast(snap)); const app = new OpenAPIHono(); app.use("/imports/*", customRateLimit({ window: "1m", max: 10 })); app.route("/imports", createImportRoutes({ service })); ``` ## API Reference - `createImportRoutes(deps: ImportRoutesDeps): OpenAPIHono` - `interface ImportRoutesDeps { service: ImportService }` ## Implementation Notes - The `requireAuth()` middleware is mounted via `app.use("/*", ...)` so every route inherits the guard. Mounting per-route would duplicate the wiring and miss the OpenAPI catch-all. - `ownerOf(c)` returns the empty string when `c.get("user")` is null; the auth middleware throws BEFORE the handler runs, so the empty string is unreachable from production traffic — but it remains a safe default if a caller somehow bypasses the middleware in a test harness. - The list endpoint returns `{ items, total }` rather than a raw array so clients can paginate; the schema enforces `total >= 0`. - The delete endpoint surfaces a `{ deleted: boolean }` payload — a successful delete returns `{ deleted: true }`; a missing job throws `IMPORT.NOT_FOUND` from the service layer and is rendered as 404.