drizzle-multitenant 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/types.ts","../src/pool.ts","../src/manager.ts","../src/context.ts","../src/migrator/migrator.ts","../src/cross-schema/cross-schema.ts"],"names":["Pool","join"],"mappings":"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","file":"index.js","sourcesContent":["import type { Config } from './types.js';\n\n/**\n * Define configuration for drizzle-multitenant\n *\n * @example\n * ```typescript\n * import { defineConfig } from 'drizzle-multitenant';\n * import * as tenantSchema from './schemas/tenant';\n * import * as sharedSchema from './schemas/shared';\n *\n * export default defineConfig({\n * connection: {\n * url: process.env.DATABASE_URL!,\n * poolConfig: {\n * max: 10,\n * idleTimeoutMillis: 30000,\n * },\n * },\n * isolation: {\n * strategy: 'schema',\n * schemaNameTemplate: (tenantId) => `tenant_${tenantId.replace(/-/g, '_')}`,\n * maxPools: 50,\n * poolTtlMs: 60 * 60 * 1000,\n * },\n * schemas: {\n * tenant: tenantSchema,\n * shared: sharedSchema,\n * },\n * });\n * ```\n */\nexport function defineConfig<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n>(config: Config<TTenantSchema, TSharedSchema>): Config<TTenantSchema, TSharedSchema> {\n validateConfig(config);\n return config;\n}\n\n/**\n * Validate configuration at runtime\n */\nfunction validateConfig<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n>(config: Config<TTenantSchema, TSharedSchema>): void {\n // Connection validation\n if (!config.connection.url) {\n throw new Error('[drizzle-multitenant] connection.url is required');\n }\n\n // Isolation validation\n if (!config.isolation.strategy) {\n throw new Error('[drizzle-multitenant] isolation.strategy is required');\n }\n\n if (config.isolation.strategy !== 'schema') {\n throw new Error(\n `[drizzle-multitenant] isolation.strategy \"${config.isolation.strategy}\" is not yet supported. Only \"schema\" is currently available.`\n );\n }\n\n if (!config.isolation.schemaNameTemplate) {\n throw new Error('[drizzle-multitenant] isolation.schemaNameTemplate is required');\n }\n\n if (typeof config.isolation.schemaNameTemplate !== 'function') {\n throw new Error('[drizzle-multitenant] isolation.schemaNameTemplate must be a function');\n }\n\n // Schema validation\n if (!config.schemas.tenant) {\n throw new Error('[drizzle-multitenant] schemas.tenant is required');\n }\n\n // Pool limits validation\n if (config.isolation.maxPools !== undefined && config.isolation.maxPools < 1) {\n throw new Error('[drizzle-multitenant] isolation.maxPools must be at least 1');\n }\n\n if (config.isolation.poolTtlMs !== undefined && config.isolation.poolTtlMs < 0) {\n throw new Error('[drizzle-multitenant] isolation.poolTtlMs must be non-negative');\n }\n}\n","import type { Pool, PoolConfig } from 'pg';\nimport type { NodePgDatabase } from 'drizzle-orm/node-postgres';\n\n/**\n * Isolation strategy for multi-tenancy\n */\nexport type IsolationStrategy = 'schema' | 'database' | 'row';\n\n/**\n * Connection configuration\n */\nexport interface ConnectionConfig {\n /** PostgreSQL connection URL */\n url: string;\n /** Pool configuration options */\n poolConfig?: Omit<PoolConfig, 'connectionString'>;\n}\n\n/**\n * Isolation configuration\n */\nexport interface IsolationConfig {\n /** Isolation strategy (currently only 'schema' is supported) */\n strategy: IsolationStrategy;\n /** Function to generate schema name from tenant ID */\n schemaNameTemplate: (tenantId: string) => string;\n /** Maximum number of simultaneous pools (LRU eviction) */\n maxPools?: number;\n /** TTL in milliseconds before pool cleanup */\n poolTtlMs?: number;\n}\n\n/**\n * Schema definitions\n */\nexport interface SchemasConfig<\n TTenantSchema extends Record<string, unknown> = Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n> {\n /** Schema applied per tenant */\n tenant: TTenantSchema;\n /** Shared schema (public) */\n shared?: TSharedSchema;\n}\n\n/**\n * Lifecycle hooks\n */\nexport interface Hooks {\n /** Called when a new pool is created */\n onPoolCreated?: (tenantId: string) => void | Promise<void>;\n /** Called when a pool is evicted */\n onPoolEvicted?: (tenantId: string) => void | Promise<void>;\n /** Called on pool error */\n onError?: (tenantId: string, error: Error) => void | Promise<void>;\n}\n\n/**\n * Metrics configuration\n */\nexport interface MetricsConfig {\n /** Enable metrics collection */\n enabled: boolean;\n /** Prefix for metric names */\n prefix?: string;\n}\n\n/**\n * Main configuration interface\n */\nexport interface Config<\n TTenantSchema extends Record<string, unknown> = Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n> {\n /** Database connection settings */\n connection: ConnectionConfig;\n /** Tenant isolation settings */\n isolation: IsolationConfig;\n /** Drizzle schemas */\n schemas: SchemasConfig<TTenantSchema, TSharedSchema>;\n /** Lifecycle hooks */\n hooks?: Hooks;\n /** Metrics configuration */\n metrics?: MetricsConfig;\n}\n\n/**\n * Internal pool entry for LRU cache\n */\nexport interface PoolEntry<TSchema extends Record<string, unknown> = Record<string, unknown>> {\n /** Drizzle database instance */\n db: NodePgDatabase<TSchema>;\n /** PostgreSQL pool */\n pool: Pool;\n /** Last access timestamp */\n lastAccess: number;\n /** Schema name */\n schemaName: string;\n}\n\n/**\n * Type for tenant database instance\n */\nexport type TenantDb<TSchema extends Record<string, unknown> = Record<string, unknown>> =\n NodePgDatabase<TSchema>;\n\n/**\n * Type for shared database instance\n */\nexport type SharedDb<TSchema extends Record<string, unknown> = Record<string, unknown>> =\n NodePgDatabase<TSchema>;\n\n/**\n * Tenant manager interface\n */\nexport interface TenantManager<\n TTenantSchema extends Record<string, unknown> = Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n> {\n /** Get database instance for a specific tenant */\n getDb(tenantId: string): TenantDb<TTenantSchema>;\n /** Get shared database instance */\n getSharedDb(): SharedDb<TSharedSchema>;\n /** Get the schema name for a tenant */\n getSchemaName(tenantId: string): string;\n /** Check if a tenant pool exists */\n hasPool(tenantId: string): boolean;\n /** Get active pool count */\n getPoolCount(): number;\n /** Get all active tenant IDs */\n getActiveTenantIds(): string[];\n /** Manually evict a tenant pool */\n evictPool(tenantId: string): Promise<void>;\n /** Dispose all pools and cleanup */\n dispose(): Promise<void>;\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG = {\n maxPools: 50,\n poolTtlMs: 60 * 60 * 1000, // 1 hour\n cleanupIntervalMs: 60_000, // 1 minute\n poolConfig: {\n max: 10,\n idleTimeoutMillis: 30_000,\n connectionTimeoutMillis: 5_000,\n },\n} as const;\n","import { Pool } from 'pg';\nimport { drizzle } from 'drizzle-orm/node-postgres';\nimport { LRUCache } from 'lru-cache';\nimport type {\n Config,\n PoolEntry,\n TenantDb,\n SharedDb,\n} from './types.js';\nimport { DEFAULT_CONFIG as defaults } from './types.js';\n\n/**\n * Pool manager that handles tenant database connections with LRU eviction\n */\nexport class PoolManager<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n> {\n private readonly pools: LRUCache<string, PoolEntry<TTenantSchema>>;\n private readonly tenantIdBySchema: Map<string, string> = new Map();\n private sharedPool: Pool | null = null;\n private sharedDb: SharedDb<TSharedSchema> | null = null;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n private disposed = false;\n\n constructor(private readonly config: Config<TTenantSchema, TSharedSchema>) {\n const maxPools = config.isolation.maxPools ?? defaults.maxPools;\n\n this.pools = new LRUCache<string, PoolEntry<TTenantSchema>>({\n max: maxPools,\n dispose: (entry, key) => {\n this.disposePoolEntry(entry, key);\n },\n noDisposeOnSet: true,\n });\n }\n\n /**\n * Get or create a database connection for a tenant\n */\n getDb(tenantId: string): TenantDb<TTenantSchema> {\n this.ensureNotDisposed();\n\n const schemaName = this.config.isolation.schemaNameTemplate(tenantId);\n let entry = this.pools.get(schemaName);\n\n if (!entry) {\n entry = this.createPoolEntry(tenantId, schemaName);\n this.pools.set(schemaName, entry);\n this.tenantIdBySchema.set(schemaName, tenantId);\n\n // Fire hook asynchronously\n void this.config.hooks?.onPoolCreated?.(tenantId);\n }\n\n entry.lastAccess = Date.now();\n return entry.db;\n }\n\n /**\n * Get or create the shared database connection\n */\n getSharedDb(): SharedDb<TSharedSchema> {\n this.ensureNotDisposed();\n\n if (!this.sharedDb) {\n this.sharedPool = new Pool({\n connectionString: this.config.connection.url,\n ...defaults.poolConfig,\n ...this.config.connection.poolConfig,\n });\n\n this.sharedPool.on('error', (err) => {\n void this.config.hooks?.onError?.('shared', err);\n });\n\n this.sharedDb = drizzle(this.sharedPool, {\n schema: this.config.schemas.shared,\n }) as SharedDb<TSharedSchema>;\n }\n\n return this.sharedDb;\n }\n\n /**\n * Get schema name for a tenant\n */\n getSchemaName(tenantId: string): string {\n return this.config.isolation.schemaNameTemplate(tenantId);\n }\n\n /**\n * Check if a pool exists for a tenant\n */\n hasPool(tenantId: string): boolean {\n const schemaName = this.config.isolation.schemaNameTemplate(tenantId);\n return this.pools.has(schemaName);\n }\n\n /**\n * Get count of active pools\n */\n getPoolCount(): number {\n return this.pools.size;\n }\n\n /**\n * Get all active tenant IDs\n */\n getActiveTenantIds(): string[] {\n return Array.from(this.tenantIdBySchema.values());\n }\n\n /**\n * Manually evict a tenant pool\n */\n async evictPool(tenantId: string): Promise<void> {\n const schemaName = this.config.isolation.schemaNameTemplate(tenantId);\n const entry = this.pools.get(schemaName);\n\n if (entry) {\n this.pools.delete(schemaName);\n this.tenantIdBySchema.delete(schemaName);\n await this.closePool(entry.pool, tenantId);\n }\n }\n\n /**\n * Start automatic cleanup of idle pools\n */\n startCleanup(): void {\n if (this.cleanupInterval) return;\n\n const poolTtlMs = this.config.isolation.poolTtlMs ?? defaults.poolTtlMs;\n const cleanupIntervalMs = defaults.cleanupIntervalMs;\n\n this.cleanupInterval = setInterval(() => {\n void this.cleanupIdlePools(poolTtlMs);\n }, cleanupIntervalMs);\n\n // Don't prevent process exit\n this.cleanupInterval.unref();\n }\n\n /**\n * Stop automatic cleanup\n */\n stopCleanup(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /**\n * Dispose all pools and cleanup resources\n */\n async dispose(): Promise<void> {\n if (this.disposed) return;\n\n this.disposed = true;\n this.stopCleanup();\n\n // Close all tenant pools\n const closePromises: Promise<void>[] = [];\n\n for (const [schemaName, entry] of this.pools.entries()) {\n const tenantId = this.tenantIdBySchema.get(schemaName);\n closePromises.push(this.closePool(entry.pool, tenantId ?? schemaName));\n }\n\n this.pools.clear();\n this.tenantIdBySchema.clear();\n\n // Close shared pool\n if (this.sharedPool) {\n closePromises.push(this.closePool(this.sharedPool, 'shared'));\n this.sharedPool = null;\n this.sharedDb = null;\n }\n\n await Promise.all(closePromises);\n }\n\n /**\n * Create a new pool entry for a tenant\n */\n private createPoolEntry(tenantId: string, schemaName: string): PoolEntry<TTenantSchema> {\n const pool = new Pool({\n connectionString: this.config.connection.url,\n ...defaults.poolConfig,\n ...this.config.connection.poolConfig,\n options: `-c search_path=${schemaName},public`,\n });\n\n pool.on('error', async (err) => {\n void this.config.hooks?.onError?.(tenantId, err);\n await this.evictPool(tenantId);\n });\n\n const db = drizzle(pool, {\n schema: this.config.schemas.tenant,\n }) as TenantDb<TTenantSchema>;\n\n return {\n db,\n pool,\n lastAccess: Date.now(),\n schemaName,\n };\n }\n\n /**\n * Dispose a pool entry (called by LRU cache)\n */\n private disposePoolEntry(entry: PoolEntry<TTenantSchema>, schemaName: string): void {\n const tenantId = this.tenantIdBySchema.get(schemaName);\n this.tenantIdBySchema.delete(schemaName);\n\n void this.closePool(entry.pool, tenantId ?? schemaName).then(() => {\n if (tenantId) {\n void this.config.hooks?.onPoolEvicted?.(tenantId);\n }\n });\n }\n\n /**\n * Close a pool gracefully\n */\n private async closePool(pool: Pool, identifier: string): Promise<void> {\n try {\n await pool.end();\n } catch (error) {\n void this.config.hooks?.onError?.(identifier, error as Error);\n }\n }\n\n /**\n * Cleanup pools that have been idle for too long\n */\n private async cleanupIdlePools(poolTtlMs: number): Promise<void> {\n const now = Date.now();\n const toEvict: string[] = [];\n\n for (const [schemaName, entry] of this.pools.entries()) {\n if (now - entry.lastAccess > poolTtlMs) {\n toEvict.push(schemaName);\n }\n }\n\n for (const schemaName of toEvict) {\n const tenantId = this.tenantIdBySchema.get(schemaName);\n if (tenantId) {\n await this.evictPool(tenantId);\n }\n }\n }\n\n /**\n * Ensure the manager hasn't been disposed\n */\n private ensureNotDisposed(): void {\n if (this.disposed) {\n throw new Error('[drizzle-multitenant] TenantManager has been disposed');\n }\n }\n}\n","import { PoolManager } from './pool.js';\nimport type { Config, TenantManager, TenantDb, SharedDb } from './types.js';\n\n/**\n * Create a tenant manager instance\n *\n * @example\n * ```typescript\n * import { createTenantManager, defineConfig } from 'drizzle-multitenant';\n *\n * const config = defineConfig({\n * connection: { url: process.env.DATABASE_URL! },\n * isolation: {\n * strategy: 'schema',\n * schemaNameTemplate: (id) => `tenant_${id}`,\n * },\n * schemas: { tenant: tenantSchema },\n * });\n *\n * const tenants = createTenantManager(config);\n *\n * // Get database for a specific tenant\n * const db = tenants.getDb('tenant-uuid');\n * const users = await db.select().from(schema.users);\n *\n * // Get shared database\n * const sharedDb = tenants.getSharedDb();\n * const plans = await sharedDb.select().from(sharedSchema.plans);\n * ```\n */\nexport function createTenantManager<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n>(config: Config<TTenantSchema, TSharedSchema>): TenantManager<TTenantSchema, TSharedSchema> {\n const poolManager = new PoolManager(config);\n\n // Start automatic cleanup\n poolManager.startCleanup();\n\n return {\n getDb(tenantId: string): TenantDb<TTenantSchema> {\n return poolManager.getDb(tenantId);\n },\n\n getSharedDb(): SharedDb<TSharedSchema> {\n return poolManager.getSharedDb();\n },\n\n getSchemaName(tenantId: string): string {\n return poolManager.getSchemaName(tenantId);\n },\n\n hasPool(tenantId: string): boolean {\n return poolManager.hasPool(tenantId);\n },\n\n getPoolCount(): number {\n return poolManager.getPoolCount();\n },\n\n getActiveTenantIds(): string[] {\n return poolManager.getActiveTenantIds();\n },\n\n async evictPool(tenantId: string): Promise<void> {\n await poolManager.evictPool(tenantId);\n },\n\n async dispose(): Promise<void> {\n await poolManager.dispose();\n },\n };\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport type { TenantManager, TenantDb, SharedDb } from './types.js';\n\n/**\n * Base tenant context data\n */\nexport interface BaseTenantContext {\n tenantId: string;\n}\n\n/**\n * Tenant context with optional custom data\n */\nexport type TenantContextData<TCustom extends Record<string, unknown> = Record<string, unknown>> =\n BaseTenantContext & TCustom;\n\n/**\n * Tenant context API\n */\nexport interface TenantContext<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n TCustom extends Record<string, unknown> = Record<string, unknown>,\n> {\n /**\n * Run a callback with tenant context\n */\n runWithTenant<T>(\n context: TenantContextData<TCustom>,\n callback: () => T | Promise<T>\n ): T | Promise<T>;\n\n /**\n * Get current tenant context (throws if not in context)\n */\n getTenant(): TenantContextData<TCustom>;\n\n /**\n * Get current tenant context or undefined\n */\n getTenantOrNull(): TenantContextData<TCustom> | undefined;\n\n /**\n * Get current tenant ID (throws if not in context)\n */\n getTenantId(): string;\n\n /**\n * Get database for current tenant (throws if not in context)\n */\n getTenantDb(): TenantDb<TTenantSchema>;\n\n /**\n * Get shared database\n */\n getSharedDb(): SharedDb<TSharedSchema>;\n\n /**\n * Check if currently running within a tenant context\n */\n isInTenantContext(): boolean;\n}\n\n/**\n * Create a tenant context with AsyncLocalStorage\n *\n * @example\n * ```typescript\n * import { createTenantContext, createTenantManager } from 'drizzle-multitenant';\n *\n * const manager = createTenantManager(config);\n *\n * const {\n * runWithTenant,\n * getTenant,\n * getTenantDb,\n * getSharedDb,\n * } = createTenantContext(manager);\n *\n * // Use in request handler\n * app.get('/users', async (req, res) => {\n * const tenantId = req.headers['x-tenant-id'];\n *\n * await runWithTenant({ tenantId }, async () => {\n * const db = getTenantDb();\n * const users = await db.select().from(schema.users);\n * res.json(users);\n * });\n * });\n * ```\n */\nexport function createTenantContext<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n TCustom extends Record<string, unknown> = Record<string, unknown>,\n>(\n manager: TenantManager<TTenantSchema, TSharedSchema>\n): TenantContext<TTenantSchema, TSharedSchema, TCustom> {\n const storage = new AsyncLocalStorage<TenantContextData<TCustom>>();\n\n function getTenantOrNull(): TenantContextData<TCustom> | undefined {\n return storage.getStore();\n }\n\n function getTenant(): TenantContextData<TCustom> {\n const context = getTenantOrNull();\n if (!context) {\n throw new Error(\n '[drizzle-multitenant] No tenant context found. ' +\n 'Make sure you are calling this within runWithTenant().'\n );\n }\n return context;\n }\n\n function getTenantId(): string {\n return getTenant().tenantId;\n }\n\n function getTenantDb(): TenantDb<TTenantSchema> {\n const tenantId = getTenantId();\n return manager.getDb(tenantId);\n }\n\n function getSharedDb(): SharedDb<TSharedSchema> {\n return manager.getSharedDb();\n }\n\n function isInTenantContext(): boolean {\n return getTenantOrNull() !== undefined;\n }\n\n function runWithTenant<T>(\n context: TenantContextData<TCustom>,\n callback: () => T | Promise<T>\n ): T | Promise<T> {\n if (!context.tenantId) {\n throw new Error('[drizzle-multitenant] tenantId is required in context');\n }\n return storage.run(context, callback);\n }\n\n return {\n runWithTenant,\n getTenant,\n getTenantOrNull,\n getTenantId,\n getTenantDb,\n getSharedDb,\n isInTenantContext,\n };\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport { join, basename } from 'node:path';\nimport { Pool } from 'pg';\nimport type { Config } from '../types.js';\nimport type {\n MigratorConfig,\n MigrationFile,\n MigrateOptions,\n TenantMigrationResult,\n MigrationResults,\n TenantMigrationStatus,\n AppliedMigration,\n CreateTenantOptions,\n DropTenantOptions,\n} from './types.js';\n\nconst DEFAULT_MIGRATIONS_TABLE = '__drizzle_migrations';\n\n/**\n * Parallel migration engine for multi-tenant applications\n */\nexport class Migrator<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n> {\n private readonly migrationsTable: string;\n\n constructor(\n private readonly tenantConfig: Config<TTenantSchema, TSharedSchema>,\n private readonly migratorConfig: MigratorConfig\n ) {\n this.migrationsTable = migratorConfig.migrationsTable ?? DEFAULT_MIGRATIONS_TABLE;\n }\n\n /**\n * Migrate all tenants in parallel\n */\n async migrateAll(options: MigrateOptions = {}): Promise<MigrationResults> {\n const {\n concurrency = 10,\n onProgress,\n onError,\n dryRun = false,\n } = options;\n\n const tenantIds = await this.migratorConfig.tenantDiscovery();\n const migrations = await this.loadMigrations();\n\n const results: TenantMigrationResult[] = [];\n let aborted = false;\n\n // Process tenants in batches\n for (let i = 0; i < tenantIds.length && !aborted; i += concurrency) {\n const batch = tenantIds.slice(i, i + concurrency);\n\n const batchResults = await Promise.all(\n batch.map(async (tenantId) => {\n if (aborted) {\n return this.createSkippedResult(tenantId);\n }\n\n try {\n onProgress?.(tenantId, 'starting');\n const result = await this.migrateTenant(tenantId, migrations, { dryRun, onProgress });\n onProgress?.(tenantId, result.success ? 'completed' : 'failed');\n return result;\n } catch (error) {\n onProgress?.(tenantId, 'failed');\n const action = onError?.(tenantId, error as Error);\n if (action === 'abort') {\n aborted = true;\n }\n return this.createErrorResult(tenantId, error as Error);\n }\n })\n );\n\n results.push(...batchResults);\n }\n\n // Mark remaining tenants as skipped if aborted\n if (aborted) {\n const remaining = tenantIds.slice(results.length);\n for (const tenantId of remaining) {\n results.push(this.createSkippedResult(tenantId));\n }\n }\n\n return this.aggregateResults(results);\n }\n\n /**\n * Migrate a single tenant\n */\n async migrateTenant(\n tenantId: string,\n migrations?: MigrationFile[],\n options: { dryRun?: boolean; onProgress?: MigrateOptions['onProgress'] } = {}\n ): Promise<TenantMigrationResult> {\n const startTime = Date.now();\n const schemaName = this.tenantConfig.isolation.schemaNameTemplate(tenantId);\n const appliedMigrations: string[] = [];\n\n const pool = await this.createPool(schemaName);\n\n try {\n await this.migratorConfig.hooks?.beforeTenant?.(tenantId);\n\n // Ensure migrations table exists\n await this.ensureMigrationsTable(pool, schemaName);\n\n // Load migrations if not provided\n const allMigrations = migrations ?? await this.loadMigrations();\n\n // Get applied migrations\n const applied = await this.getAppliedMigrations(pool, schemaName);\n const appliedSet = new Set(applied.map((m) => m.name));\n\n // Filter pending migrations\n const pending = allMigrations.filter((m) => !appliedSet.has(m.name));\n\n if (options.dryRun) {\n return {\n tenantId,\n schemaName,\n success: true,\n appliedMigrations: pending.map((m) => m.name),\n durationMs: Date.now() - startTime,\n };\n }\n\n // Apply pending migrations\n for (const migration of pending) {\n const migrationStart = Date.now();\n options.onProgress?.(tenantId, 'migrating', migration.name);\n\n await this.migratorConfig.hooks?.beforeMigration?.(tenantId, migration.name);\n await this.applyMigration(pool, schemaName, migration);\n await this.migratorConfig.hooks?.afterMigration?.(\n tenantId,\n migration.name,\n Date.now() - migrationStart\n );\n\n appliedMigrations.push(migration.name);\n }\n\n const result: TenantMigrationResult = {\n tenantId,\n schemaName,\n success: true,\n appliedMigrations,\n durationMs: Date.now() - startTime,\n };\n\n await this.migratorConfig.hooks?.afterTenant?.(tenantId, result);\n\n return result;\n } catch (error) {\n const result: TenantMigrationResult = {\n tenantId,\n schemaName,\n success: false,\n appliedMigrations,\n error: (error as Error).message,\n durationMs: Date.now() - startTime,\n };\n\n await this.migratorConfig.hooks?.afterTenant?.(tenantId, result);\n\n return result;\n } finally {\n await pool.end();\n }\n }\n\n /**\n * Migrate specific tenants\n */\n async migrateTenants(tenantIds: string[], options: MigrateOptions = {}): Promise<MigrationResults> {\n const migrations = await this.loadMigrations();\n const results: TenantMigrationResult[] = [];\n\n const { concurrency = 10, onProgress, onError } = options;\n\n for (let i = 0; i < tenantIds.length; i += concurrency) {\n const batch = tenantIds.slice(i, i + concurrency);\n\n const batchResults = await Promise.all(\n batch.map(async (tenantId) => {\n try {\n onProgress?.(tenantId, 'starting');\n const result = await this.migrateTenant(tenantId, migrations, { dryRun: options.dryRun ?? false, onProgress });\n onProgress?.(tenantId, result.success ? 'completed' : 'failed');\n return result;\n } catch (error) {\n onProgress?.(tenantId, 'failed');\n onError?.(tenantId, error as Error);\n return this.createErrorResult(tenantId, error as Error);\n }\n })\n );\n\n results.push(...batchResults);\n }\n\n return this.aggregateResults(results);\n }\n\n /**\n * Get migration status for all tenants\n */\n async getStatus(): Promise<TenantMigrationStatus[]> {\n const tenantIds = await this.migratorConfig.tenantDiscovery();\n const migrations = await this.loadMigrations();\n const statuses: TenantMigrationStatus[] = [];\n\n for (const tenantId of tenantIds) {\n statuses.push(await this.getTenantStatus(tenantId, migrations));\n }\n\n return statuses;\n }\n\n /**\n * Get migration status for a specific tenant\n */\n async getTenantStatus(tenantId: string, migrations?: MigrationFile[]): Promise<TenantMigrationStatus> {\n const schemaName = this.tenantConfig.isolation.schemaNameTemplate(tenantId);\n const pool = await this.createPool(schemaName);\n\n try {\n const allMigrations = migrations ?? await this.loadMigrations();\n\n // Check if migrations table exists\n const tableExists = await this.migrationsTableExists(pool, schemaName);\n if (!tableExists) {\n return {\n tenantId,\n schemaName,\n appliedCount: 0,\n pendingCount: allMigrations.length,\n pendingMigrations: allMigrations.map((m) => m.name),\n status: allMigrations.length > 0 ? 'behind' : 'ok',\n };\n }\n\n const applied = await this.getAppliedMigrations(pool, schemaName);\n const appliedSet = new Set(applied.map((m) => m.name));\n const pending = allMigrations.filter((m) => !appliedSet.has(m.name));\n\n return {\n tenantId,\n schemaName,\n appliedCount: applied.length,\n pendingCount: pending.length,\n pendingMigrations: pending.map((m) => m.name),\n status: pending.length > 0 ? 'behind' : 'ok',\n };\n } catch (error) {\n return {\n tenantId,\n schemaName,\n appliedCount: 0,\n pendingCount: 0,\n pendingMigrations: [],\n status: 'error',\n error: (error as Error).message,\n };\n } finally {\n await pool.end();\n }\n }\n\n /**\n * Create a new tenant schema and optionally apply migrations\n */\n async createTenant(tenantId: string, options: CreateTenantOptions = {}): Promise<void> {\n const { migrate = true } = options;\n const schemaName = this.tenantConfig.isolation.schemaNameTemplate(tenantId);\n\n const pool = new Pool({\n connectionString: this.tenantConfig.connection.url,\n ...this.tenantConfig.connection.poolConfig,\n });\n\n try {\n // Create schema\n await pool.query(`CREATE SCHEMA IF NOT EXISTS \"${schemaName}\"`);\n\n if (migrate) {\n // Apply all migrations\n await this.migrateTenant(tenantId);\n }\n } finally {\n await pool.end();\n }\n }\n\n /**\n * Drop a tenant schema\n */\n async dropTenant(tenantId: string, options: DropTenantOptions = {}): Promise<void> {\n const { cascade = true } = options;\n const schemaName = this.tenantConfig.isolation.schemaNameTemplate(tenantId);\n\n const pool = new Pool({\n connectionString: this.tenantConfig.connection.url,\n ...this.tenantConfig.connection.poolConfig,\n });\n\n try {\n const cascadeSql = cascade ? 'CASCADE' : 'RESTRICT';\n await pool.query(`DROP SCHEMA IF EXISTS \"${schemaName}\" ${cascadeSql}`);\n } finally {\n await pool.end();\n }\n }\n\n /**\n * Check if a tenant schema exists\n */\n async tenantExists(tenantId: string): Promise<boolean> {\n const schemaName = this.tenantConfig.isolation.schemaNameTemplate(tenantId);\n\n const pool = new Pool({\n connectionString: this.tenantConfig.connection.url,\n ...this.tenantConfig.connection.poolConfig,\n });\n\n try {\n const result = await pool.query(\n `SELECT 1 FROM information_schema.schemata WHERE schema_name = $1`,\n [schemaName]\n );\n return result.rowCount !== null && result.rowCount > 0;\n } finally {\n await pool.end();\n }\n }\n\n /**\n * Load migration files from the migrations folder\n */\n private async loadMigrations(): Promise<MigrationFile[]> {\n const files = await readdir(this.migratorConfig.migrationsFolder);\n\n const migrations: MigrationFile[] = [];\n\n for (const file of files) {\n if (!file.endsWith('.sql')) continue;\n\n const filePath = join(this.migratorConfig.migrationsFolder, file);\n const content = await readFile(filePath, 'utf-8');\n\n // Extract timestamp from filename (e.g., 0001_migration_name.sql)\n const match = file.match(/^(\\d+)_/);\n const timestamp = match?.[1] ? parseInt(match[1], 10) : 0;\n\n migrations.push({\n name: basename(file, '.sql'),\n path: filePath,\n sql: content,\n timestamp,\n });\n }\n\n // Sort by timestamp\n return migrations.sort((a, b) => a.timestamp - b.timestamp);\n }\n\n /**\n * Create a pool for a specific schema\n */\n private async createPool(schemaName: string): Promise<Pool> {\n return new Pool({\n connectionString: this.tenantConfig.connection.url,\n ...this.tenantConfig.connection.poolConfig,\n options: `-c search_path=\"${schemaName}\",public`,\n });\n }\n\n /**\n * Ensure migrations table exists\n */\n private async ensureMigrationsTable(pool: Pool, schemaName: string): Promise<void> {\n await pool.query(`\n CREATE TABLE IF NOT EXISTS \"${schemaName}\".\"${this.migrationsTable}\" (\n id SERIAL PRIMARY KEY,\n name VARCHAR(255) NOT NULL UNIQUE,\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP\n )\n `);\n }\n\n /**\n * Check if migrations table exists\n */\n private async migrationsTableExists(pool: Pool, schemaName: string): Promise<boolean> {\n const result = await pool.query(\n `SELECT 1 FROM information_schema.tables\n WHERE table_schema = $1 AND table_name = $2`,\n [schemaName, this.migrationsTable]\n );\n return result.rowCount !== null && result.rowCount > 0;\n }\n\n /**\n * Get applied migrations for a schema\n */\n private async getAppliedMigrations(pool: Pool, schemaName: string): Promise<AppliedMigration[]> {\n const result = await pool.query<{ id: number; name: string; applied_at: Date }>(\n `SELECT id, name, applied_at FROM \"${schemaName}\".\"${this.migrationsTable}\" ORDER BY id`\n );\n return result.rows.map((row) => ({\n id: row.id,\n name: row.name,\n appliedAt: row.applied_at,\n }));\n }\n\n /**\n * Apply a migration to a schema\n */\n private async applyMigration(pool: Pool, schemaName: string, migration: MigrationFile): Promise<void> {\n const client = await pool.connect();\n\n try {\n await client.query('BEGIN');\n\n // Execute migration SQL\n await client.query(migration.sql);\n\n // Record migration\n await client.query(\n `INSERT INTO \"${schemaName}\".\"${this.migrationsTable}\" (name) VALUES ($1)`,\n [migration.name]\n );\n\n await client.query('COMMIT');\n } catch (error) {\n await client.query('ROLLBACK');\n throw error;\n } finally {\n client.release();\n }\n }\n\n /**\n * Create a skipped result\n */\n private createSkippedResult(tenantId: string): TenantMigrationResult {\n return {\n tenantId,\n schemaName: this.tenantConfig.isolation.schemaNameTemplate(tenantId),\n success: false,\n appliedMigrations: [],\n error: 'Skipped due to abort',\n durationMs: 0,\n };\n }\n\n /**\n * Create an error result\n */\n private createErrorResult(tenantId: string, error: Error): TenantMigrationResult {\n return {\n tenantId,\n schemaName: this.tenantConfig.isolation.schemaNameTemplate(tenantId),\n success: false,\n appliedMigrations: [],\n error: error.message,\n durationMs: 0,\n };\n }\n\n /**\n * Aggregate migration results\n */\n private aggregateResults(results: TenantMigrationResult[]): MigrationResults {\n return {\n total: results.length,\n succeeded: results.filter((r) => r.success).length,\n failed: results.filter((r) => !r.success && r.error !== 'Skipped due to abort').length,\n skipped: results.filter((r) => r.error === 'Skipped due to abort').length,\n details: results,\n };\n }\n}\n\n/**\n * Create a migrator instance\n */\nexport function createMigrator<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n>(\n tenantConfig: Config<TTenantSchema, TSharedSchema>,\n migratorConfig: MigratorConfig\n): Migrator<TTenantSchema, TSharedSchema> {\n return new Migrator(tenantConfig, migratorConfig);\n}\n","import { sql, getTableName } from 'drizzle-orm';\nimport type { NodePgDatabase } from 'drizzle-orm/node-postgres';\nimport type { SQL, Table, Column } from 'drizzle-orm';\nimport type {\n CrossSchemaContext,\n SchemaSource,\n JoinType,\n JoinCondition,\n SharedLookupConfig,\n CrossSchemaRawOptions,\n} from './types.js';\n\n/**\n * Cross-schema query builder for joining tenant and shared data\n *\n * @example\n * ```typescript\n * const query = createCrossSchemaQuery({\n * tenantDb: tenants.getDb('tenant-uuid'),\n * sharedDb: tenants.getSharedDb(),\n * });\n *\n * const results = await query\n * .from('tenant', orders)\n * .leftJoin('shared', subscriptionPlans, eq(orders.planId, subscriptionPlans.id))\n * .select({\n * orderId: orders.id,\n * planName: subscriptionPlans.name,\n * })\n * .execute();\n * ```\n */\nexport class CrossSchemaQueryBuilder<\n TTenantSchema extends Record<string, unknown> = Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n> {\n private fromTable: { table: Table; source: SchemaSource; schemaName: string } | null = null;\n private joins: Array<{\n table: Table;\n source: SchemaSource;\n schemaName: string;\n condition: JoinCondition;\n type: JoinType;\n }> = [];\n private selectFields: Record<string, Column> = {};\n private whereCondition: SQL<unknown> | null = null;\n private orderByFields: SQL<unknown>[] = [];\n private limitValue: number | null = null;\n private offsetValue: number | null = null;\n\n constructor(private readonly context: CrossSchemaContext<TTenantSchema, TSharedSchema>) {}\n\n /**\n * Set the main table to query from\n */\n from<T extends Table>(source: SchemaSource, table: T): this {\n const schemaName = this.getSchemaName(source);\n this.fromTable = { table, source, schemaName };\n return this;\n }\n\n /**\n * Add an inner join\n */\n innerJoin<T extends Table>(source: SchemaSource, table: T, condition: JoinCondition): this {\n return this.addJoin(source, table, condition, 'inner');\n }\n\n /**\n * Add a left join\n */\n leftJoin<T extends Table>(source: SchemaSource, table: T, condition: JoinCondition): this {\n return this.addJoin(source, table, condition, 'left');\n }\n\n /**\n * Add a right join\n */\n rightJoin<T extends Table>(source: SchemaSource, table: T, condition: JoinCondition): this {\n return this.addJoin(source, table, condition, 'right');\n }\n\n /**\n * Add a full outer join\n */\n fullJoin<T extends Table>(source: SchemaSource, table: T, condition: JoinCondition): this {\n return this.addJoin(source, table, condition, 'full');\n }\n\n /**\n * Select specific fields\n */\n select<T extends Record<string, Column>>(fields: T): this {\n this.selectFields = fields;\n return this;\n }\n\n /**\n * Add a where condition\n */\n where(condition: SQL<unknown>): this {\n this.whereCondition = condition;\n return this;\n }\n\n /**\n * Add order by\n */\n orderBy(...fields: SQL<unknown>[]): this {\n this.orderByFields = fields;\n return this;\n }\n\n /**\n * Set limit\n */\n limit(value: number): this {\n this.limitValue = value;\n return this;\n }\n\n /**\n * Set offset\n */\n offset(value: number): this {\n this.offsetValue = value;\n return this;\n }\n\n /**\n * Execute the query and return typed results\n */\n async execute<TResult = Record<string, unknown>>(): Promise<TResult[]> {\n if (!this.fromTable) {\n throw new Error('[drizzle-multitenant] No table specified. Use .from() first.');\n }\n\n const sqlQuery = this.buildSql();\n\n // Use the tenant db to execute (it has access to both schemas via search_path)\n const result = await this.context.tenantDb.execute(sqlQuery);\n\n return result.rows as TResult[];\n }\n\n /**\n * Build the SQL query\n */\n private buildSql(): SQL<unknown> {\n if (!this.fromTable) {\n throw new Error('[drizzle-multitenant] No table specified');\n }\n\n const parts: SQL<unknown>[] = [];\n\n // SELECT clause\n const selectParts = Object.entries(this.selectFields).map(([alias, column]) => {\n const columnName = column.name;\n return sql`${sql.raw(`\"${columnName}\"`)} as ${sql.raw(`\"${alias}\"`)}`;\n });\n\n if (selectParts.length === 0) {\n parts.push(sql`SELECT *`);\n } else {\n parts.push(sql`SELECT ${sql.join(selectParts, sql`, `)}`);\n }\n\n // FROM clause\n const fromTableRef = this.getFullTableName(this.fromTable.schemaName, this.fromTable.table);\n parts.push(sql` FROM ${sql.raw(fromTableRef)}`);\n\n // JOIN clauses\n for (const join of this.joins) {\n const joinTableRef = this.getFullTableName(join.schemaName, join.table);\n const joinType = this.getJoinKeyword(join.type);\n parts.push(sql` ${sql.raw(joinType)} ${sql.raw(joinTableRef)} ON ${join.condition}`);\n }\n\n // WHERE clause\n if (this.whereCondition) {\n parts.push(sql` WHERE ${this.whereCondition}`);\n }\n\n // ORDER BY clause\n if (this.orderByFields.length > 0) {\n parts.push(sql` ORDER BY ${sql.join(this.orderByFields, sql`, `)}`);\n }\n\n // LIMIT clause\n if (this.limitValue !== null) {\n parts.push(sql` LIMIT ${sql.raw(this.limitValue.toString())}`);\n }\n\n // OFFSET clause\n if (this.offsetValue !== null) {\n parts.push(sql` OFFSET ${sql.raw(this.offsetValue.toString())}`);\n }\n\n return sql.join(parts, sql``);\n }\n\n /**\n * Add a join to the query\n */\n private addJoin<T extends Table>(\n source: SchemaSource,\n table: T,\n condition: JoinCondition,\n type: JoinType\n ): this {\n const schemaName = this.getSchemaName(source);\n this.joins.push({ table, source, schemaName, condition, type });\n return this;\n }\n\n /**\n * Get schema name for a source\n */\n private getSchemaName(source: SchemaSource): string {\n if (source === 'tenant') {\n return this.context.tenantSchema ?? 'tenant';\n }\n return this.context.sharedSchema ?? 'public';\n }\n\n /**\n * Get fully qualified table name\n */\n private getFullTableName(schemaName: string, table: Table): string {\n const tableName = getTableName(table);\n return `\"${schemaName}\".\"${tableName}\"`;\n }\n\n /**\n * Get SQL keyword for join type\n */\n private getJoinKeyword(type: JoinType): string {\n switch (type) {\n case 'inner':\n return 'INNER JOIN';\n case 'left':\n return 'LEFT JOIN';\n case 'right':\n return 'RIGHT JOIN';\n case 'full':\n return 'FULL OUTER JOIN';\n }\n }\n}\n\n/**\n * Create a cross-schema query builder\n */\nexport function createCrossSchemaQuery<\n TTenantSchema extends Record<string, unknown> = Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n>(\n context: CrossSchemaContext<TTenantSchema, TSharedSchema>\n): CrossSchemaQueryBuilder<TTenantSchema, TSharedSchema> {\n return new CrossSchemaQueryBuilder(context);\n}\n\n/**\n * Helper for common pattern: tenant table with shared lookup\n *\n * @example\n * ```typescript\n * const ordersWithPlans = await withSharedLookup({\n * tenantDb,\n * sharedDb,\n * tenantTable: orders,\n * sharedTable: subscriptionPlans,\n * foreignKey: 'planId',\n * sharedFields: ['name', 'features', 'price'],\n * });\n * ```\n */\nexport async function withSharedLookup<\n TTenantTable extends Table,\n TSharedTable extends Table,\n TSharedFields extends keyof TSharedTable['_']['columns'],\n>(config: SharedLookupConfig<TTenantTable, TSharedTable, TSharedFields>): Promise<Array<Record<string, unknown>>> {\n const {\n tenantDb,\n tenantTable,\n sharedTable,\n foreignKey,\n sharedKey = 'id' as keyof TSharedTable['_']['columns'],\n sharedFields,\n where: whereCondition,\n } = config;\n\n // Get table names using Drizzle's utility\n const tenantTableName = getTableName(tenantTable);\n const sharedTableName = getTableName(sharedTable);\n\n // Build field list for shared table\n const sharedFieldList = sharedFields\n .map((field) => `s.\"${String(field)}\"`)\n .join(', ');\n\n // Build the query\n const queryParts = [\n `SELECT t.*, ${sharedFieldList}`,\n `FROM \"${tenantTableName}\" t`,\n `LEFT JOIN \"public\".\"${sharedTableName}\" s ON t.\"${String(foreignKey)}\" = s.\"${String(sharedKey)}\"`,\n ];\n\n if (whereCondition) {\n queryParts.push('WHERE');\n // We'll need to use raw SQL for the where condition\n }\n\n const sqlQuery = sql.raw(queryParts.join(' '));\n\n const result = await tenantDb.execute(sqlQuery);\n\n return result.rows as Array<Record<string, unknown>>;\n}\n\n/**\n * Execute raw cross-schema SQL with type safety\n *\n * @example\n * ```typescript\n * const result = await crossSchemaRaw<{ userName: string; planName: string }>({\n * tenantSchema: 'tenant_abc123',\n * sharedSchema: 'public',\n * sql: `\n * SELECT u.name as \"userName\", p.name as \"planName\"\n * FROM $tenant.users u\n * JOIN $shared.plans p ON u.plan_id = p.id\n * `,\n * });\n * ```\n */\nexport async function crossSchemaRaw<TResult = Record<string, unknown>>(\n db: NodePgDatabase<Record<string, unknown>>,\n options: CrossSchemaRawOptions\n): Promise<TResult[]> {\n const { tenantSchema, sharedSchema, sql: rawSql } = options;\n\n // Replace $tenant and $shared placeholders\n const processedSql = rawSql\n .replace(/\\$tenant\\./g, `\"${tenantSchema}\".`)\n .replace(/\\$shared\\./g, `\"${sharedSchema}\".`);\n\n const query = sql.raw(processedSql);\n\n const result = await db.execute(query);\n\n return result.rows as TResult[];\n}\n\n/**\n * Create a typed cross-schema query using SQL template\n *\n * @example\n * ```typescript\n * const users = await crossSchemaSelect(tenantDb, {\n * tenantSchema: 'tenant_abc',\n * sharedSchema: 'public',\n * select: {\n * id: users.id,\n * name: users.name,\n * planName: plans.name,\n * },\n * from: { table: users, schema: 'tenant' },\n * joins: [\n * { table: plans, schema: 'shared', on: eq(users.planId, plans.id), type: 'left' },\n * ],\n * });\n * ```\n */\nexport function buildCrossSchemaSelect<T extends Record<string, Column>>(\n fields: T,\n tenantSchema: string,\n _sharedSchema: string\n): { columns: string[]; getSchema: () => string } {\n const columns = Object.entries(fields).map(([alias, column]) => {\n const columnName = column.name;\n return `\"${columnName}\" as \"${alias}\"`;\n });\n\n const getSchema = (): string => {\n // This would need more context to determine which schema a column belongs to\n // For now, return tenant schema as default\n return tenantSchema;\n };\n\n return { columns, getSchema };\n}\n"]}
@@ -0,0 +1,93 @@
1
+ import { Request, Response, NextFunction, RequestHandler } from 'express';
2
+ import { T as TenantManager } from '../types-DKVaTaIb.js';
3
+ import { T as TenantContextData, a as TenantContext } from '../context-DBerWr50.js';
4
+ export { c as createTenantContext } from '../context-DBerWr50.js';
5
+ import 'pg';
6
+ import 'drizzle-orm/node-postgres';
7
+
8
+ /**
9
+ * Express middleware options
10
+ */
11
+ interface ExpressMiddlewareOptions<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>, TCustom extends Record<string, unknown> = Record<string, unknown>> {
12
+ /** Tenant manager instance */
13
+ manager: TenantManager<TTenantSchema, TSharedSchema>;
14
+ /**
15
+ * Extract tenant ID from request
16
+ * @example
17
+ * // From header
18
+ * extractTenantId: (req) => req.headers['x-tenant-id'] as string
19
+ *
20
+ * // From path param
21
+ * extractTenantId: (req) => req.params.tenantId
22
+ *
23
+ * // From subdomain
24
+ * extractTenantId: (req) => req.hostname.split('.')[0]
25
+ */
26
+ extractTenantId: (req: Request) => string | undefined | Promise<string | undefined>;
27
+ /**
28
+ * Optional tenant validation
29
+ * Throw an error or return false to reject the request
30
+ */
31
+ validateTenant?: (tenantId: string, req: Request) => boolean | Promise<boolean>;
32
+ /**
33
+ * Enrich context with additional data
34
+ */
35
+ enrichContext?: (tenantId: string, req: Request) => TCustom | Promise<TCustom>;
36
+ /**
37
+ * Custom error handler
38
+ */
39
+ onError?: (error: Error, req: Request, res: Response, next: NextFunction) => void;
40
+ }
41
+ /**
42
+ * Tenant not found error
43
+ */
44
+ declare class TenantNotFoundError extends Error {
45
+ constructor(message?: string);
46
+ }
47
+ /**
48
+ * Tenant validation error
49
+ */
50
+ declare class TenantValidationError extends Error {
51
+ constructor(message?: string);
52
+ }
53
+ /**
54
+ * Extended Express Request with tenant context
55
+ */
56
+ interface TenantRequest<TCustom extends Record<string, unknown> = Record<string, unknown>> extends Request {
57
+ tenantContext?: TenantContextData<TCustom>;
58
+ }
59
+ /**
60
+ * Create Express middleware for tenant context
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import express from 'express';
65
+ * import { createTenantManager } from 'drizzle-multitenant';
66
+ * import { createExpressMiddleware } from 'drizzle-multitenant/express';
67
+ *
68
+ * const app = express();
69
+ * const manager = createTenantManager(config);
70
+ *
71
+ * const tenantMiddleware = createExpressMiddleware({
72
+ * manager,
73
+ * extractTenantId: (req) => req.headers['x-tenant-id'] as string,
74
+ * validateTenant: async (tenantId) => {
75
+ * // Check if tenant exists in database
76
+ * return true;
77
+ * },
78
+ * });
79
+ *
80
+ * app.use('/api', tenantMiddleware);
81
+ *
82
+ * app.get('/api/users', async (req, res) => {
83
+ * const db = getTenantDb();
84
+ * const users = await db.select().from(schema.users);
85
+ * res.json(users);
86
+ * });
87
+ * ```
88
+ */
89
+ declare function createExpressMiddleware<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>, TCustom extends Record<string, unknown> = Record<string, unknown>>(options: ExpressMiddlewareOptions<TTenantSchema, TSharedSchema, TCustom>): RequestHandler & {
90
+ context: TenantContext<TTenantSchema, TSharedSchema, TCustom>;
91
+ };
92
+
93
+ export { type ExpressMiddlewareOptions, TenantContext, TenantContextData, TenantNotFoundError, type TenantRequest, TenantValidationError, createExpressMiddleware };
@@ -0,0 +1,110 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+
3
+ // src/context.ts
4
+ function createTenantContext(manager) {
5
+ const storage = new AsyncLocalStorage();
6
+ function getTenantOrNull() {
7
+ return storage.getStore();
8
+ }
9
+ function getTenant() {
10
+ const context = getTenantOrNull();
11
+ if (!context) {
12
+ throw new Error(
13
+ "[drizzle-multitenant] No tenant context found. Make sure you are calling this within runWithTenant()."
14
+ );
15
+ }
16
+ return context;
17
+ }
18
+ function getTenantId() {
19
+ return getTenant().tenantId;
20
+ }
21
+ function getTenantDb() {
22
+ const tenantId = getTenantId();
23
+ return manager.getDb(tenantId);
24
+ }
25
+ function getSharedDb() {
26
+ return manager.getSharedDb();
27
+ }
28
+ function isInTenantContext() {
29
+ return getTenantOrNull() !== void 0;
30
+ }
31
+ function runWithTenant(context, callback) {
32
+ if (!context.tenantId) {
33
+ throw new Error("[drizzle-multitenant] tenantId is required in context");
34
+ }
35
+ return storage.run(context, callback);
36
+ }
37
+ return {
38
+ runWithTenant,
39
+ getTenant,
40
+ getTenantOrNull,
41
+ getTenantId,
42
+ getTenantDb,
43
+ getSharedDb,
44
+ isInTenantContext
45
+ };
46
+ }
47
+
48
+ // src/integrations/express.ts
49
+ var TenantNotFoundError = class extends Error {
50
+ constructor(message = "Tenant not found") {
51
+ super(message);
52
+ this.name = "TenantNotFoundError";
53
+ }
54
+ };
55
+ var TenantValidationError = class extends Error {
56
+ constructor(message = "Tenant validation failed") {
57
+ super(message);
58
+ this.name = "TenantValidationError";
59
+ }
60
+ };
61
+ function createExpressMiddleware(options) {
62
+ const { manager, extractTenantId, validateTenant, enrichContext, onError } = options;
63
+ const tenantContext = createTenantContext(manager);
64
+ const defaultErrorHandler = (error, _req, res, _next) => {
65
+ if (error instanceof TenantNotFoundError) {
66
+ res.status(400).json({ error: "Tenant ID is required" });
67
+ return;
68
+ }
69
+ if (error instanceof TenantValidationError) {
70
+ res.status(403).json({ error: "Invalid tenant" });
71
+ return;
72
+ }
73
+ res.status(500).json({ error: "Internal server error" });
74
+ };
75
+ const errorHandler = onError ?? defaultErrorHandler;
76
+ const middleware = async (req, res, next) => {
77
+ try {
78
+ const tenantId = await extractTenantId(req);
79
+ if (!tenantId) {
80
+ throw new TenantNotFoundError("Tenant ID not found in request");
81
+ }
82
+ if (validateTenant) {
83
+ const isValid = await validateTenant(tenantId, req);
84
+ if (!isValid) {
85
+ throw new TenantValidationError(`Tenant ${tenantId} validation failed`);
86
+ }
87
+ }
88
+ const customContext = enrichContext ? await enrichContext(tenantId, req) : {};
89
+ const context = {
90
+ tenantId,
91
+ ...customContext
92
+ };
93
+ req.tenantContext = context;
94
+ await tenantContext.runWithTenant(context, async () => {
95
+ await new Promise((resolve, reject) => {
96
+ next();
97
+ res.on("finish", resolve);
98
+ res.on("error", reject);
99
+ });
100
+ });
101
+ } catch (error) {
102
+ errorHandler(error, req, res, next);
103
+ }
104
+ };
105
+ return Object.assign(middleware, { context: tenantContext });
106
+ }
107
+
108
+ export { TenantNotFoundError, TenantValidationError, createExpressMiddleware, createTenantContext };
109
+ //# sourceMappingURL=express.js.map
110
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/context.ts","../../src/integrations/express.ts"],"names":[],"mappings":"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","file":"express.js","sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport type { TenantManager, TenantDb, SharedDb } from './types.js';\n\n/**\n * Base tenant context data\n */\nexport interface BaseTenantContext {\n tenantId: string;\n}\n\n/**\n * Tenant context with optional custom data\n */\nexport type TenantContextData<TCustom extends Record<string, unknown> = Record<string, unknown>> =\n BaseTenantContext & TCustom;\n\n/**\n * Tenant context API\n */\nexport interface TenantContext<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n TCustom extends Record<string, unknown> = Record<string, unknown>,\n> {\n /**\n * Run a callback with tenant context\n */\n runWithTenant<T>(\n context: TenantContextData<TCustom>,\n callback: () => T | Promise<T>\n ): T | Promise<T>;\n\n /**\n * Get current tenant context (throws if not in context)\n */\n getTenant(): TenantContextData<TCustom>;\n\n /**\n * Get current tenant context or undefined\n */\n getTenantOrNull(): TenantContextData<TCustom> | undefined;\n\n /**\n * Get current tenant ID (throws if not in context)\n */\n getTenantId(): string;\n\n /**\n * Get database for current tenant (throws if not in context)\n */\n getTenantDb(): TenantDb<TTenantSchema>;\n\n /**\n * Get shared database\n */\n getSharedDb(): SharedDb<TSharedSchema>;\n\n /**\n * Check if currently running within a tenant context\n */\n isInTenantContext(): boolean;\n}\n\n/**\n * Create a tenant context with AsyncLocalStorage\n *\n * @example\n * ```typescript\n * import { createTenantContext, createTenantManager } from 'drizzle-multitenant';\n *\n * const manager = createTenantManager(config);\n *\n * const {\n * runWithTenant,\n * getTenant,\n * getTenantDb,\n * getSharedDb,\n * } = createTenantContext(manager);\n *\n * // Use in request handler\n * app.get('/users', async (req, res) => {\n * const tenantId = req.headers['x-tenant-id'];\n *\n * await runWithTenant({ tenantId }, async () => {\n * const db = getTenantDb();\n * const users = await db.select().from(schema.users);\n * res.json(users);\n * });\n * });\n * ```\n */\nexport function createTenantContext<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown> = Record<string, unknown>,\n TCustom extends Record<string, unknown> = Record<string, unknown>,\n>(\n manager: TenantManager<TTenantSchema, TSharedSchema>\n): TenantContext<TTenantSchema, TSharedSchema, TCustom> {\n const storage = new AsyncLocalStorage<TenantContextData<TCustom>>();\n\n function getTenantOrNull(): TenantContextData<TCustom> | undefined {\n return storage.getStore();\n }\n\n function getTenant(): TenantContextData<TCustom> {\n const context = getTenantOrNull();\n if (!context) {\n throw new Error(\n '[drizzle-multitenant] No tenant context found. ' +\n 'Make sure you are calling this within runWithTenant().'\n );\n }\n return context;\n }\n\n function getTenantId(): string {\n return getTenant().tenantId;\n }\n\n function getTenantDb(): TenantDb<TTenantSchema> {\n const tenantId = getTenantId();\n return manager.getDb(tenantId);\n }\n\n function getSharedDb(): SharedDb<TSharedSchema> {\n return manager.getSharedDb();\n }\n\n function isInTenantContext(): boolean {\n return getTenantOrNull() !== undefined;\n }\n\n function runWithTenant<T>(\n context: TenantContextData<TCustom>,\n callback: () => T | Promise<T>\n ): T | Promise<T> {\n if (!context.tenantId) {\n throw new Error('[drizzle-multitenant] tenantId is required in context');\n }\n return storage.run(context, callback);\n }\n\n return {\n runWithTenant,\n getTenant,\n getTenantOrNull,\n getTenantId,\n getTenantDb,\n getSharedDb,\n isInTenantContext,\n };\n}\n","import type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport type { TenantManager } from '../types.js';\nimport { createTenantContext, type TenantContext, type TenantContextData } from '../context.js';\n\n/**\n * Express middleware options\n */\nexport interface ExpressMiddlewareOptions<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n TCustom extends Record<string, unknown> = Record<string, unknown>,\n> {\n /** Tenant manager instance */\n manager: TenantManager<TTenantSchema, TSharedSchema>;\n\n /**\n * Extract tenant ID from request\n * @example\n * // From header\n * extractTenantId: (req) => req.headers['x-tenant-id'] as string\n *\n * // From path param\n * extractTenantId: (req) => req.params.tenantId\n *\n * // From subdomain\n * extractTenantId: (req) => req.hostname.split('.')[0]\n */\n extractTenantId: (req: Request) => string | undefined | Promise<string | undefined>;\n\n /**\n * Optional tenant validation\n * Throw an error or return false to reject the request\n */\n validateTenant?: (tenantId: string, req: Request) => boolean | Promise<boolean>;\n\n /**\n * Enrich context with additional data\n */\n enrichContext?: (tenantId: string, req: Request) => TCustom | Promise<TCustom>;\n\n /**\n * Custom error handler\n */\n onError?: (error: Error, req: Request, res: Response, next: NextFunction) => void;\n}\n\n/**\n * Tenant not found error\n */\nexport class TenantNotFoundError extends Error {\n constructor(message = 'Tenant not found') {\n super(message);\n this.name = 'TenantNotFoundError';\n }\n}\n\n/**\n * Tenant validation error\n */\nexport class TenantValidationError extends Error {\n constructor(message = 'Tenant validation failed') {\n super(message);\n this.name = 'TenantValidationError';\n }\n}\n\n/**\n * Extended Express Request with tenant context\n */\nexport interface TenantRequest<TCustom extends Record<string, unknown> = Record<string, unknown>>\n extends Request {\n tenantContext?: TenantContextData<TCustom>;\n}\n\n/**\n * Create Express middleware for tenant context\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { createTenantManager } from 'drizzle-multitenant';\n * import { createExpressMiddleware } from 'drizzle-multitenant/express';\n *\n * const app = express();\n * const manager = createTenantManager(config);\n *\n * const tenantMiddleware = createExpressMiddleware({\n * manager,\n * extractTenantId: (req) => req.headers['x-tenant-id'] as string,\n * validateTenant: async (tenantId) => {\n * // Check if tenant exists in database\n * return true;\n * },\n * });\n *\n * app.use('/api', tenantMiddleware);\n *\n * app.get('/api/users', async (req, res) => {\n * const db = getTenantDb();\n * const users = await db.select().from(schema.users);\n * res.json(users);\n * });\n * ```\n */\nexport function createExpressMiddleware<\n TTenantSchema extends Record<string, unknown>,\n TSharedSchema extends Record<string, unknown>,\n TCustom extends Record<string, unknown> = Record<string, unknown>,\n>(\n options: ExpressMiddlewareOptions<TTenantSchema, TSharedSchema, TCustom>\n): RequestHandler & {\n context: TenantContext<TTenantSchema, TSharedSchema, TCustom>;\n} {\n const { manager, extractTenantId, validateTenant, enrichContext, onError } = options;\n\n const tenantContext = createTenantContext<TTenantSchema, TSharedSchema, TCustom>(manager);\n\n const defaultErrorHandler = (\n error: Error,\n _req: Request,\n res: Response,\n _next: NextFunction\n ): void => {\n if (error instanceof TenantNotFoundError) {\n res.status(400).json({ error: 'Tenant ID is required' });\n return;\n }\n if (error instanceof TenantValidationError) {\n res.status(403).json({ error: 'Invalid tenant' });\n return;\n }\n res.status(500).json({ error: 'Internal server error' });\n };\n\n const errorHandler = onError ?? defaultErrorHandler;\n\n const middleware: RequestHandler = async (\n req: TenantRequest<TCustom>,\n res: Response,\n next: NextFunction\n ): Promise<void> => {\n try {\n const tenantId = await extractTenantId(req);\n\n if (!tenantId) {\n throw new TenantNotFoundError('Tenant ID not found in request');\n }\n\n if (validateTenant) {\n const isValid = await validateTenant(tenantId, req);\n if (!isValid) {\n throw new TenantValidationError(`Tenant ${tenantId} validation failed`);\n }\n }\n\n const customContext = enrichContext ? await enrichContext(tenantId, req) : ({} as TCustom);\n\n const context: TenantContextData<TCustom> = {\n tenantId,\n ...customContext,\n };\n\n req.tenantContext = context;\n\n await tenantContext.runWithTenant(context, async () => {\n await new Promise<void>((resolve, reject) => {\n next();\n res.on('finish', resolve);\n res.on('error', reject);\n });\n });\n } catch (error) {\n errorHandler(error as Error, req, res, next);\n }\n };\n\n return Object.assign(middleware, { context: tenantContext });\n}\n\n/**\n * Re-export context utilities for convenience\n */\nexport { createTenantContext, type TenantContext, type TenantContextData } from '../context.js';\n"]}
@@ -0,0 +1,92 @@
1
+ import { FastifyRequest, FastifyReply, FastifyPluginAsync } from 'fastify';
2
+ import { T as TenantManager } from '../types-DKVaTaIb.js';
3
+ import { T as TenantContextData, a as TenantContext } from '../context-DBerWr50.js';
4
+ export { c as createTenantContext } from '../context-DBerWr50.js';
5
+ import 'pg';
6
+ import 'drizzle-orm/node-postgres';
7
+
8
+ /**
9
+ * Fastify plugin options
10
+ */
11
+ interface FastifyPluginOptions<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>, TCustom extends Record<string, unknown> = Record<string, unknown>> {
12
+ /** Tenant manager instance */
13
+ manager: TenantManager<TTenantSchema, TSharedSchema>;
14
+ /**
15
+ * Extract tenant ID from request
16
+ * @example
17
+ * // From header
18
+ * extractTenantId: (req) => req.headers['x-tenant-id'] as string
19
+ *
20
+ * // From path param
21
+ * extractTenantId: (req) => (req.params as any).tenantId
22
+ *
23
+ * // From subdomain
24
+ * extractTenantId: (req) => req.hostname.split('.')[0]
25
+ */
26
+ extractTenantId: (req: FastifyRequest) => string | undefined | Promise<string | undefined>;
27
+ /**
28
+ * Optional tenant validation
29
+ * Throw an error or return false to reject the request
30
+ */
31
+ validateTenant?: (tenantId: string, req: FastifyRequest) => boolean | Promise<boolean>;
32
+ /**
33
+ * Enrich context with additional data
34
+ */
35
+ enrichContext?: (tenantId: string, req: FastifyRequest) => TCustom | Promise<TCustom>;
36
+ /**
37
+ * Custom error handler
38
+ */
39
+ onError?: (error: Error, req: FastifyRequest, reply: FastifyReply) => void | Promise<void>;
40
+ }
41
+ /**
42
+ * Tenant not found error
43
+ */
44
+ declare class TenantNotFoundError extends Error {
45
+ constructor(message?: string);
46
+ }
47
+ /**
48
+ * Tenant validation error
49
+ */
50
+ declare class TenantValidationError extends Error {
51
+ constructor(message?: string);
52
+ }
53
+ /**
54
+ * Fastify request decorator
55
+ */
56
+ declare module 'fastify' {
57
+ interface FastifyRequest {
58
+ tenantContext?: TenantContextData<Record<string, unknown>>;
59
+ }
60
+ }
61
+ /**
62
+ * Create Fastify plugin for tenant context
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * import Fastify from 'fastify';
67
+ * import { createTenantManager } from 'drizzle-multitenant';
68
+ * import { createFastifyPlugin } from 'drizzle-multitenant/fastify';
69
+ *
70
+ * const fastify = Fastify();
71
+ * const manager = createTenantManager(config);
72
+ *
73
+ * const { plugin, context } = createFastifyPlugin({
74
+ * manager,
75
+ * extractTenantId: (req) => req.headers['x-tenant-id'] as string,
76
+ * });
77
+ *
78
+ * await fastify.register(plugin);
79
+ *
80
+ * fastify.get('/users', async (req, reply) => {
81
+ * const db = context.getTenantDb();
82
+ * const users = await db.select().from(schema.users);
83
+ * return users;
84
+ * });
85
+ * ```
86
+ */
87
+ declare function createFastifyPlugin<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>, TCustom extends Record<string, unknown> = Record<string, unknown>>(options: FastifyPluginOptions<TTenantSchema, TSharedSchema, TCustom>): {
88
+ plugin: FastifyPluginAsync;
89
+ context: TenantContext<TTenantSchema, TSharedSchema, TCustom>;
90
+ };
91
+
92
+ export { type FastifyPluginOptions, TenantContext, TenantContextData, TenantNotFoundError, TenantValidationError, createFastifyPlugin };