Files
skills/docs/api-stack/api/api-plugin-tenant/README.md
2026-05-29 08:20:56 +01:00

122 lines
7.5 KiB
Markdown

# @suaveplan/api-plugin-tenant - Multi-tenancy plugin for @suaveplan/api. Exposes @suaveplan/api-tenant's resolver chain (header / subdomain / domain / path / JWT / query / cookie) as a first-class definePlugin slot, wires TenantCache, installs the per-request resolving middleware, registers a typed tenantService in the ServiceRegistry, and (when a TenantStore is configured) mounts admin-gated CRUD routes. Server-tier. Composes with @suaveplan/api-plugin-auth's requireRole when present for RBAC on the management routes.
Multi-tenancy plugin for `@suaveplan/api`. Wraps
`@suaveplan/api-tenant`'s resolver chain (header / subdomain / domain /
path / JWT / query / cookie) as a first-class `definePlugin` slot,
wires `TenantCache`, installs the per-request resolving middleware,
registers a typed `tenantService` in the host `ServiceRegistry`, and
(when a `TenantStore` is configured) mounts admin-gated CRUD routes
under a configurable prefix.
<!-- begin:auto-docs -->
## Documentation tree
- [error-codes](./src/error-codes/error-codes.md) — Defines the stable error-code registry for `@suaveplan/api-plugin-tenant` and the concrete `TenantPluginError` class th…
- [error-codes](./src/error-codes/error-codes.md) — Defines the stable error-code registry for `@suaveplan/api-plugin-tenant` and the concrete `TenantPluginError` class th…
- [middleware](./src/middleware/tenant.md) — Provides `buildTenantPluginMiddleware`, the Hono middleware factory the plugin installs on `ctx.app` during `onInit`. T…
- [tenant](./src/middleware/tenant.md) — Provides `buildTenantPluginMiddleware`, the Hono middleware factory the plugin installs on `ctx.app` during `onInit`. T…
- [otel](./src/otel/instruments.md) — Lazily resolves the OpenTelemetry instruments (`Counter`, `Histogram`) the plugin emits from its production paths. The…
- [instruments](./src/otel/instruments.md) — Lazily resolves the OpenTelemetry instruments (`Counter`, `Histogram`) the plugin emits from its production paths. The…
- [plugin](./src/plugin/plugin.md) — Exposes `createTenantPlugin`, the factory that returns a typed `PluginDescriptor` consumable by the `@suaveplan/api` or…
- [build-resolver](./src/plugin/build-resolver.md) — Composes the strategy specs from the plugin's options into a single `TenantResolver` chain, optionally wrapped with `Te…
- [plugin](./src/plugin/plugin.md) — Exposes `createTenantPlugin`, the factory that returns a typed `PluginDescriptor` consumable by the `@suaveplan/api` or…
- [routes](./src/routes/routes.md) — Builds the five OpenAPI route entries `createTenantPlugin` mounts when a `TenantStore` is configured: `GET /`, `POST /`…
- [routes](./src/routes/routes.md) — Builds the five OpenAPI route entries `createTenantPlugin` mounts when a `TenantStore` is configured: `GET /`, `POST /`…
- [options](./src/schemas/options.md) — Defines the Zod schema validated at the `createTenantPlugin` boundary plus the strategy-spec discriminated-union schema…
- [routes](./src/schemas/routes.md) — Defines the Zod request/response schemas the five management routes mount when the plugin is configured with a `TenantS…
- [registry-augmentation](./src/services/registry-augmentation.md) — Side-effect module that declares the `tenantService` slot on `@suaveplan/api-plugin`'s `ServiceRegistry` interface so c…
- [tenant-service](./src/services/tenant-service.md) — Defines the `TenantService` interface registered into the host `ServiceRegistry` by `createTenantPlugin` and the factor…
- [store](./src/store/store.md) — Defines the canonical `TenantStore` persistence contract every `@suaveplan/api-plugin-tenant` backend honours. The inte…
- [memory](./src/store/memory.md) — Ships the default `MemoryTenantStore` — a synchronous in-memory implementation of the `TenantStore` interface suitable…
- [store](./src/store/store.md) — Defines the canonical `TenantStore` persistence contract every `@suaveplan/api-plugin-tenant` backend honours. The inte…
- [types](./src/types/types.md) — Defines the public option shapes accepted by `createTenantPlugin` and the resolved-config shape stored on the returned…
- [types](./src/types/types.md) — Defines the public option shapes accepted by `createTenantPlugin` and the resolved-config shape stored on the returned…
<!-- end:auto-docs -->
## Install
```bash
bun add @suaveplan/api-plugin-tenant
```
## Quick start
```ts
import { defineApp } from "@suaveplan/api";
import { createAuthPlugin } from "@suaveplan/api-plugin-auth";
import { createTenantPlugin, MemoryTenantStore } from "@suaveplan/api-plugin-tenant";
const app = defineApp({
plugins: [
createAuthPlugin({ betterAuth: { /* ... */ } }),
createTenantPlugin({
strategies: [
{ type: "header", headerName: "x-tenant-id" },
{ type: "cookie", cookieName: "tenant" },
{ type: "subdomain", baseDomain: "app.example.com" },
{ type: "jwt", claimName: "tenantId" },
{ type: "path", prefix: "/t/" },
{ type: "query", paramName: "tenant" },
],
cache: { ttlMs: 60_000, negativeTtlMs: 5_000, maxEntries: 10_000 },
required: false,
store: new MemoryTenantStore(),
}),
],
});
```
## What you get
- **Seven resolver strategies** composed in priority order — first
non-null wins. The chain is wrapped with `TenantCache` when a
`cache` config is supplied.
- **Per-request `c.set("tenant", tenant)`** via the inner
`createTenantMiddleware` from `@suaveplan/api-tenant`. Status gating
(`deleted` / `suspended` / `pending`) is enforced before the handler
runs.
- **`tenantService` registry slot** — `resolveFrom`, `requireFrom`,
`current`, `getById`, `listAll`, `createTenant`, `updateTenant`,
`deleteTenant`, `getResolver`.
- **Five CRUD routes** mounted when `store` is supplied:
`GET /tenants`, `POST /tenants`, `GET /tenants/:id`,
`PATCH /tenants/:id`, `DELETE /tenants/:id`. Every body and query
flows through a strict Zod schema, so the unified OpenAPI 3.1 doc
matches the runtime surface.
- **Optional admin RBAC** — when `@suaveplan/api-plugin-auth` is
loaded, the CRUD routes are gated by `requireRole("admin")`. Without
it, the plugin logs a warning so operators do not silently expose
admin endpoints.
- **OpenTelemetry instruments** — `tenant_plugin.resolutions_total`,
`tenant_plugin.resolution_duration_ms`, `tenant_plugin.cache_total`,
`tenant_plugin.management_ops_total`.
- **Seven stable `TENANT_PLUGIN.*` error codes** — surfaced via
`TenantPluginError extends SuaveplanError`.
## Modules
- [`error-codes/error-codes.md`](./src/error-codes/error-codes.md)
- [`types/types.md`](./src/types/types.md)
- [`store/store.md`](./src/store/store.md)
- [`store/memory.md`](./src/store/memory.md)
- [`schemas/options.md`](./src/schemas/options.md)
- [`schemas/routes.md`](./src/schemas/routes.md)
- [`services/tenant-service.md`](./src/services/tenant-service.md)
- [`services/registry-augmentation.md`](./src/services/registry-augmentation.md)
- [`middleware/tenant.md`](./src/middleware/tenant.md)
- [`otel/instruments.md`](./src/otel/instruments.md)
- [`plugin/build-resolver.md`](./src/plugin/build-resolver.md)
- [`plugin/plugin.md`](./src/plugin/plugin.md)
- [`routes/routes.md`](./src/routes/routes.md)
## Error codes
`TENANT_PLUGIN.INVALID_INPUT`, `STORE_NOT_CONFIGURED`,
`SERVICE_NOT_AVAILABLE`, `ROUTE_PREFIX_COLLISION`, `TENANT_NOT_FOUND`,
`TENANT_SLUG_TAKEN`, `RESOLVER_BUILD_FAILED`.
## License
MIT