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,85 @@
# `routes`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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.