express-multitenancy
Version:
Express middleware for managing multi-tenant applications with configurable tenant resolution strategies
230 lines (229 loc) • 7.96 kB
TypeScript
import { Request } from 'express';
/**
* Interface for tenant identification strategies.
*
* Implement this interface to create custom strategies for identifying
* the current tenant from an incoming request. This allows for
* flexible tenant resolution based on different parts of the request.
*/
export interface Strategy {
/**
* Resolves the tenant ID from the request.
*
* @param req - Express request object to analyze for tenant information
* @returns A Promise resolving to the tenant ID string if found, or null if no tenant could be identified
*/
resolveTenantId(req: Request): Promise<string | null>;
}
/**
* Strategy for identifying tenants based on HTTP headers.
*
* This strategy extracts the tenant ID from a specified HTTP header.
* It's a common approach for API-based multi-tenant applications.
*
* @example
* ```
* // Create a strategy that looks for tenant ID in x-tenant-id header
* const headerStrategy = new HeaderStrategy('x-tenant-id');
* ```
*/
export declare class HeaderStrategy implements Strategy {
private headerName;
/**
* Creates a new HeaderStrategy instance.
*
* @param headerName - The name of the HTTP header containing the tenant ID (case insensitive)
* Defaults to 'x-tenant-id' if not provided.
*/
constructor(headerName?: string);
/**
* Extracts tenant ID from the specified HTTP header.
*
* @param req - Express request object
* @returns The tenant ID from the header, or null if header is not present
*/
resolveTenantId(req: Request): Promise<string | null>;
}
/**
* Strategy for identifying tenants based on hostname.
*
* This strategy extracts the tenant ID from the hostname using a regular expression pattern.
* It's useful for subdomain-based multi-tenancy (e.g., tenant1.example.com).
*
* @example
* ```
* // Create a strategy that extracts tenant ID from subdomain
* const hostStrategy = new HostStrategy(/^([^.]+)/); // matches "tenant1" from "tenant1.example.com"
* ```
*/
export declare class HostStrategy implements Strategy {
private pattern;
/**
* Creates a new HostStrategy instance.
*
* @param pattern - Regular expression pattern with a capture group for the tenant ID
*/
constructor(pattern: RegExp);
/**
* Extracts tenant ID from the hostname using the provided regex pattern.
*
* @param req - Express request object
* @returns The tenant ID extracted from hostname, or null if no match
*/
resolveTenantId(req: Request): Promise<string | null>;
}
/**
* Strategy for identifying tenants based on route parameters.
*
* This strategy extracts the tenant ID from route parameters.
* It's useful for route-based multi-tenancy (e.g., /api/:tenantId/resources).
*
* @example
* ```
* // Define a route with tenant parameter
* app.get('/api/:tenantId/resources', (req, res) => { ... });
*
* // Create a strategy that extracts tenant ID from route parameter
* const routeStrategy = new RouteStrategy('tenantId');
*
* // For Express 5 compatibility, mount the middleware on specific routes
* app.use(['/api/:tenantId', '/api/:tenantId/*'], multitenancy({
* strategies: [routeStrategy],
* store: myStore
* }));
* ```
*/
export declare class RouteStrategy implements Strategy {
private paramName;
/**
* Creates a new RouteStrategy instance.
*
* @param paramName - Name of the route parameter to extract as tenant ID (default: 'tenantId')
*/
constructor(paramName?: string);
/**
* Extracts tenant ID from the route parameter specified in constructor.
*
* @param req - Express request object
* @returns The tenant ID from route parameter, or null if not present
*/
resolveTenantId(req: Request): Promise<string | null>;
}
/**
* Options for the BasePathStrategy.
*/
export interface BasePathOptions {
/**
* If true, the tenant path segment will be removed from req.path after tenant resolution,
* making the rest of the application unaware of the tenant segment in the URL.
* For example, "/tenant1/api/resources" becomes "/api/resources".
*/
rebasePath?: boolean;
/**
* The position of the path segment to use as tenant ID (1-based index).
* For example, if the URL is "/tenant1/api/resources", and position is 1,
* the tenant ID will be "tenant1".
*/
position: number;
}
/**
* Strategy for identifying tenants based on URL path segments.
*
* This strategy extracts the tenant ID from a specific segment of the URL path.
* It's useful for path-based multi-tenancy (e.g., /tenant1/api/resources).
*
* @example
* ```
* // Create a strategy that uses the first path segment as tenant ID
* const basePathStrategy = new BasePathStrategy({ position: 1 }); // extracts "tenant1" from "/tenant1/api/resources"
*
* // Create a strategy that also rebases the path (removes the tenant segment)
* const basePathStrategy = new BasePathStrategy({ rebasePath: true });
* // After tenant resolution, "/tenant1/api/resources" becomes "/api/resources"
* ```
*/
export declare class BasePathStrategy implements Strategy {
private options;
/**
* Creates a new BasePathStrategy instance.
*
* @param options - Configuration options for the strategy
*/
constructor(options?: Partial<BasePathOptions>);
/**
* Extracts tenant ID from the specified position in the URL path.
*
* @param req - Express request object
* @returns The tenant ID from the path segment, or null if not present
*/
resolveTenantId(req: Request): Promise<string | null>;
}
/**
* Represents a JWT or authentication payload with flexible structure
*/
export interface AuthPayload {
[key: string]: unknown;
}
/**
* Options for the ClaimStrategy.
*/
export interface ClaimStrategyOptions {
/**
* Optional function to extract the auth payload from the request
* If not provided, the strategy will try to extract from Authorization header
*/
authExtractor?: (req: Request) => AuthPayload | null;
/**
* Whether to enable debug logging for claim extraction
* Default: false
*/
debug?: boolean;
}
/**
* Strategy for identifying tenants based on authentication claims.
*
* This strategy extracts the tenant ID from JWT claims or other auth tokens.
* It's useful for applications where tenant context is tied to user authentication.
*
* @example
* ```
* // Create a strategy that extracts tenant ID from a specific claim
* const claimStrategy = new ClaimStrategy('tenantId');
*
* // Extract from nested claim property
* const nestedClaimStrategy = new ClaimStrategy('app_metadata.tenant_id');
*
* // With custom auth extractor
* const customStrategy = new ClaimStrategy('tenant', {
* authExtractor: (req) => req.user // For passport or similar auth middleware
* });
* ```
*/
export declare class ClaimStrategy implements Strategy {
private claimPath;
private authExtractor;
private debug;
/**
* Creates a new ClaimStrategy instance.
*
* @param claimPath - Path to the claim containing tenant ID (dot notation for nested properties)
* @param options - Configuration options for the strategy
*/
constructor(claimPath: string, options?: ClaimStrategyOptions);
/**
* Extracts tenant ID from the authentication claims.
*
* @param req - Express request object
* @returns The tenant ID from the claims, or null if not found
*/
resolveTenantId(req: Request): Promise<string | null>;
/**
* Default extractor that looks for JWT in Authorization header.
* This handles "Bearer <token>" format and attempts to decode the JWT.
*/
private defaultAuthExtractor;
/**
* Gets a nested property from an object using dot notation.
*/
private getNestedProperty;
}