3.0 KiB
tenant
(no submodules)
Purpose
Provides buildTenantPluginMiddleware, the Hono middleware factory
the plugin installs on ctx.app during onInit. The factory composes
createTenantMiddleware from @suaveplan/api-tenant (the canonical
resolver + status-gate implementation) with an outer wrapper that
records OTel resolution timing and outcome for every request. The
result is a single middleware that handles per-request tenant
resolution, fail-closed behaviour, and observability.
Features
- Delegates the core resolution + status-gate (
deleted/suspended/pending) to the well-tested@suaveplan/api-tenantmiddleware. - Wraps every invocation with
performance.now()timing so the OTel histogram captures real latency, including the inner middleware's work. - Records
tenant_plugin.resolutions_total{outcome, strategy}with outcomesresolved,missing,errorso dashboards can break down failures by strategy. - Returns the inner middleware's response verbatim — no shape changes
— so error handlers see the same
TenantErrorthey would see if they calledcreateTenantMiddlewaredirectly.
Usage: Basic Example
import { buildTenantPluginMiddleware } from "@suaveplan/api-plugin-tenant";
import { headerResolver } from "@suaveplan/api-tenant";
import { Hono } from "hono";
const resolver = headerResolver("x-tenant-id", lookupFn);
const app = new Hono();
app.use("*", buildTenantPluginMiddleware({
resolver,
required: false,
allowSuspended: false,
}));
Usage: Advanced Example
import { buildTenantPluginMiddleware } from "@suaveplan/api-plugin-tenant";
import { chainResolvers, headerResolver, subdomainResolver, TenantCache } from "@suaveplan/api-tenant";
const resolver = TenantCache.wrap(
chainResolvers(
headerResolver("x-tenant-id", store.byId),
subdomainResolver("app.example.com", store.bySlug)
),
{ ttlMs: 60_000, negativeTtlMs: 5_000, maxEntries: 10_000 }
);
app.use("*", buildTenantPluginMiddleware({
resolver,
required: true,
allowSuspended: false,
excludePaths: ["/health", "/ready", "/openapi.json", "/public"],
}));
API Reference
interface BuildTenantPluginMiddlewareOptions—{ resolver, required, allowSuspended, excludePaths? }.function buildTenantPluginMiddleware(options): MiddlewareHandler— returns a HonoMiddlewareHandlerready forapp.use("*", ...).
Implementation Notes
Timing is recorded for every code path including the rethrow path so
the histogram captures slow failures (network errors in the store,
slow JWT verifications, etc.). The outer wrapper does not call
next() directly — that responsibility stays inside
createTenantMiddleware, which also owns the short-circuit for
excludePaths. Splitting responsibilities this way means a future
upgrade of @suaveplan/api-tenant (e.g. adding sampling or distributed
tracing) lands automatically without changes to the plugin.