Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
# `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.