Files
skills/plugins/document-navigator/docs/api-stack/api/api-plugin-tenant/README.md
2026-06-09 21:06:27 +01:00

7.5 KiB

@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.

Documentation tree

  • error-codes — Defines the stable error-code registry for @suaveplan/api-plugin-tenant and the concrete TenantPluginError class th…
    • error-codes — Defines the stable error-code registry for @suaveplan/api-plugin-tenant and the concrete TenantPluginError class th…
  • middleware — Provides buildTenantPluginMiddleware, the Hono middleware factory the plugin installs on ctx.app during onInit. T…
    • tenant — Provides buildTenantPluginMiddleware, the Hono middleware factory the plugin installs on ctx.app during onInit. T…
  • otel — Lazily resolves the OpenTelemetry instruments (Counter, Histogram) the plugin emits from its production paths. The…
    • instruments — Lazily resolves the OpenTelemetry instruments (Counter, Histogram) the plugin emits from its production paths. The…
  • plugin — Exposes createTenantPlugin, the factory that returns a typed PluginDescriptor consumable by the @suaveplan/api or…
    • build-resolver — Composes the strategy specs from the plugin's options into a single TenantResolver chain, optionally wrapped with `Te…
    • plugin — Exposes createTenantPlugin, the factory that returns a typed PluginDescriptor consumable by the @suaveplan/api or…
  • routes — Builds the five OpenAPI route entries createTenantPlugin mounts when a TenantStore is configured: GET /, POST /…
    • routes — Builds the five OpenAPI route entries createTenantPlugin mounts when a TenantStore is configured: GET /, POST /…
  • options — Defines the Zod schema validated at the createTenantPlugin boundary plus the strategy-spec discriminated-union schema…
  • routes — Defines the Zod request/response schemas the five management routes mount when the plugin is configured with a `TenantS…
  • registry-augmentation — Side-effect module that declares the tenantService slot on @suaveplan/api-plugin's ServiceRegistry interface so c…
  • tenant-service — Defines the TenantService interface registered into the host ServiceRegistry by createTenantPlugin and the factor…
  • store — Defines the canonical TenantStore persistence contract every @suaveplan/api-plugin-tenant backend honours. The inte…
    • memory — Ships the default MemoryTenantStore — a synchronous in-memory implementation of the TenantStore interface suitable…
    • store — Defines the canonical TenantStore persistence contract every @suaveplan/api-plugin-tenant backend honours. The inte…
  • types — Defines the public option shapes accepted by createTenantPlugin and the resolved-config shape stored on the returned…
    • types — Defines the public option shapes accepted by createTenantPlugin and the resolved-config shape stored on the returned…

Install

bun add @suaveplan/api-plugin-tenant

Quick start

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

TENANT_PLUGIN.INVALID_INPUT, STORE_NOT_CONFIGURED, SERVICE_NOT_AVAILABLE, ROUTE_PREFIX_COLLISION, TENANT_NOT_FOUND, TENANT_SLUG_TAKEN, RESOLVER_BUILD_FAILED.

License

MIT