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,130 @@
1
+ import { PoolConfig, Pool } from 'pg';
2
+ import { NodePgDatabase } from 'drizzle-orm/node-postgres';
3
+
4
+ /**
5
+ * Isolation strategy for multi-tenancy
6
+ */
7
+ type IsolationStrategy = 'schema' | 'database' | 'row';
8
+ /**
9
+ * Connection configuration
10
+ */
11
+ interface ConnectionConfig {
12
+ /** PostgreSQL connection URL */
13
+ url: string;
14
+ /** Pool configuration options */
15
+ poolConfig?: Omit<PoolConfig, 'connectionString'>;
16
+ }
17
+ /**
18
+ * Isolation configuration
19
+ */
20
+ interface IsolationConfig {
21
+ /** Isolation strategy (currently only 'schema' is supported) */
22
+ strategy: IsolationStrategy;
23
+ /** Function to generate schema name from tenant ID */
24
+ schemaNameTemplate: (tenantId: string) => string;
25
+ /** Maximum number of simultaneous pools (LRU eviction) */
26
+ maxPools?: number;
27
+ /** TTL in milliseconds before pool cleanup */
28
+ poolTtlMs?: number;
29
+ }
30
+ /**
31
+ * Schema definitions
32
+ */
33
+ interface SchemasConfig<TTenantSchema extends Record<string, unknown> = Record<string, unknown>, TSharedSchema extends Record<string, unknown> = Record<string, unknown>> {
34
+ /** Schema applied per tenant */
35
+ tenant: TTenantSchema;
36
+ /** Shared schema (public) */
37
+ shared?: TSharedSchema;
38
+ }
39
+ /**
40
+ * Lifecycle hooks
41
+ */
42
+ interface Hooks {
43
+ /** Called when a new pool is created */
44
+ onPoolCreated?: (tenantId: string) => void | Promise<void>;
45
+ /** Called when a pool is evicted */
46
+ onPoolEvicted?: (tenantId: string) => void | Promise<void>;
47
+ /** Called on pool error */
48
+ onError?: (tenantId: string, error: Error) => void | Promise<void>;
49
+ }
50
+ /**
51
+ * Metrics configuration
52
+ */
53
+ interface MetricsConfig {
54
+ /** Enable metrics collection */
55
+ enabled: boolean;
56
+ /** Prefix for metric names */
57
+ prefix?: string;
58
+ }
59
+ /**
60
+ * Main configuration interface
61
+ */
62
+ interface Config<TTenantSchema extends Record<string, unknown> = Record<string, unknown>, TSharedSchema extends Record<string, unknown> = Record<string, unknown>> {
63
+ /** Database connection settings */
64
+ connection: ConnectionConfig;
65
+ /** Tenant isolation settings */
66
+ isolation: IsolationConfig;
67
+ /** Drizzle schemas */
68
+ schemas: SchemasConfig<TTenantSchema, TSharedSchema>;
69
+ /** Lifecycle hooks */
70
+ hooks?: Hooks;
71
+ /** Metrics configuration */
72
+ metrics?: MetricsConfig;
73
+ }
74
+ /**
75
+ * Internal pool entry for LRU cache
76
+ */
77
+ interface PoolEntry<TSchema extends Record<string, unknown> = Record<string, unknown>> {
78
+ /** Drizzle database instance */
79
+ db: NodePgDatabase<TSchema>;
80
+ /** PostgreSQL pool */
81
+ pool: Pool;
82
+ /** Last access timestamp */
83
+ lastAccess: number;
84
+ /** Schema name */
85
+ schemaName: string;
86
+ }
87
+ /**
88
+ * Type for tenant database instance
89
+ */
90
+ type TenantDb<TSchema extends Record<string, unknown> = Record<string, unknown>> = NodePgDatabase<TSchema>;
91
+ /**
92
+ * Type for shared database instance
93
+ */
94
+ type SharedDb<TSchema extends Record<string, unknown> = Record<string, unknown>> = NodePgDatabase<TSchema>;
95
+ /**
96
+ * Tenant manager interface
97
+ */
98
+ interface TenantManager<TTenantSchema extends Record<string, unknown> = Record<string, unknown>, TSharedSchema extends Record<string, unknown> = Record<string, unknown>> {
99
+ /** Get database instance for a specific tenant */
100
+ getDb(tenantId: string): TenantDb<TTenantSchema>;
101
+ /** Get shared database instance */
102
+ getSharedDb(): SharedDb<TSharedSchema>;
103
+ /** Get the schema name for a tenant */
104
+ getSchemaName(tenantId: string): string;
105
+ /** Check if a tenant pool exists */
106
+ hasPool(tenantId: string): boolean;
107
+ /** Get active pool count */
108
+ getPoolCount(): number;
109
+ /** Get all active tenant IDs */
110
+ getActiveTenantIds(): string[];
111
+ /** Manually evict a tenant pool */
112
+ evictPool(tenantId: string): Promise<void>;
113
+ /** Dispose all pools and cleanup */
114
+ dispose(): Promise<void>;
115
+ }
116
+ /**
117
+ * Default configuration values
118
+ */
119
+ declare const DEFAULT_CONFIG: {
120
+ readonly maxPools: 50;
121
+ readonly poolTtlMs: number;
122
+ readonly cleanupIntervalMs: 60000;
123
+ readonly poolConfig: {
124
+ readonly max: 10;
125
+ readonly idleTimeoutMillis: 30000;
126
+ readonly connectionTimeoutMillis: 5000;
127
+ };
128
+ };
129
+
130
+ export { type Config as C, DEFAULT_CONFIG as D, type Hooks as H, type IsolationConfig as I, type MetricsConfig as M, type PoolEntry as P, type SharedDb as S, type TenantManager as T, type TenantDb as a, type ConnectionConfig as b, type IsolationStrategy as c, type SchemasConfig as d };
package/package.json ADDED
@@ -0,0 +1,102 @@
1
+ {
2
+ "name": "drizzle-multitenant",
3
+ "version": "1.0.0",
4
+ "description": "Multi-tenancy toolkit for Drizzle ORM with schema isolation, tenant context, and parallel migrations",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./express": {
15
+ "import": "./dist/integrations/express.js",
16
+ "types": "./dist/integrations/express.d.ts"
17
+ },
18
+ "./fastify": {
19
+ "import": "./dist/integrations/fastify.js",
20
+ "types": "./dist/integrations/fastify.d.ts"
21
+ },
22
+ "./nestjs": {
23
+ "import": "./dist/integrations/nestjs/index.js",
24
+ "types": "./dist/integrations/nestjs/index.d.ts"
25
+ },
26
+ "./hono": {
27
+ "import": "./dist/integrations/hono.js",
28
+ "types": "./dist/integrations/hono.d.ts"
29
+ },
30
+ "./migrator": {
31
+ "import": "./dist/migrator/index.js",
32
+ "types": "./dist/migrator/index.d.ts"
33
+ },
34
+ "./cross-schema": {
35
+ "import": "./dist/cross-schema/index.js",
36
+ "types": "./dist/cross-schema/index.d.ts"
37
+ }
38
+ },
39
+ "bin": {
40
+ "drizzle-multitenant": "./bin/drizzle-multitenant.js"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "dev": "tsup --watch",
45
+ "test": "vitest",
46
+ "test:coverage": "vitest --coverage",
47
+ "lint": "eslint src --ext .ts",
48
+ "typecheck": "tsc --noEmit",
49
+ "prepublishOnly": "npm run build"
50
+ },
51
+ "keywords": [
52
+ "drizzle",
53
+ "drizzle-orm",
54
+ "multi-tenant",
55
+ "multitenancy",
56
+ "postgresql",
57
+ "schema-isolation",
58
+ "saas"
59
+ ],
60
+ "author": "Mateus Florez",
61
+ "license": "MIT",
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "git+https://github.com/mateusflorez/drizzle-multitenant.git"
65
+ },
66
+ "bugs": {
67
+ "url": "https://github.com/mateusflorez/drizzle-multitenant/issues"
68
+ },
69
+ "homepage": "https://github.com/mateusflorez/drizzle-multitenant#readme",
70
+ "dependencies": {
71
+ "chalk": "^5.6.2",
72
+ "cli-table3": "^0.6.5",
73
+ "commander": "^12.1.0",
74
+ "lru-cache": "^10.4.3",
75
+ "ora": "^8.2.0"
76
+ },
77
+ "peerDependencies": {
78
+ "drizzle-orm": ">=0.29.0",
79
+ "pg": ">=8.0.0"
80
+ },
81
+ "devDependencies": {
82
+ "@nestjs/common": "^10.4.20",
83
+ "@nestjs/core": "^10.4.20",
84
+ "@nestjs/testing": "^10.4.20",
85
+ "@types/express": "^5.0.6",
86
+ "@types/node": "^22.10.2",
87
+ "@types/pg": "^8.11.10",
88
+ "drizzle-orm": "^0.38.2",
89
+ "express": "^5.2.1",
90
+ "fastify": "^5.6.2",
91
+ "fastify-plugin": "^5.1.0",
92
+ "pg": "^8.13.1",
93
+ "reflect-metadata": "^0.2.2",
94
+ "rxjs": "^7.8.2",
95
+ "tsup": "^8.3.5",
96
+ "typescript": "^5.7.2",
97
+ "vitest": "^2.1.8"
98
+ },
99
+ "engines": {
100
+ "node": ">=18.0.0"
101
+ }
102
+ }