@veloxts/orm 0.6.27 → 0.6.31
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.
- package/CHANGELOG.md +32 -0
- package/GUIDE.md +102 -1
- package/dist/client.d.ts +0 -1
- package/dist/client.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/plugin.d.ts +0 -1
- package/dist/plugin.js +0 -1
- package/dist/tenant/client-pool.d.ts +38 -0
- package/dist/tenant/client-pool.js +233 -0
- package/dist/tenant/errors.d.ts +141 -0
- package/dist/tenant/errors.js +220 -0
- package/dist/tenant/index.d.ts +58 -0
- package/dist/tenant/index.js +85 -0
- package/dist/tenant/middleware.d.ts +81 -0
- package/dist/tenant/middleware.js +162 -0
- package/dist/tenant/schema/manager.d.ts +37 -0
- package/dist/tenant/schema/manager.js +334 -0
- package/dist/tenant/schema/provisioner.d.ts +32 -0
- package/dist/tenant/schema/provisioner.js +281 -0
- package/dist/tenant/types.d.ts +431 -0
- package/dist/tenant/types.js +35 -0
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -1
- package/package.json +10 -2
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @veloxts/orm
|
|
2
2
|
|
|
3
|
+
## 0.6.31
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- npm must use concurrently for run dev script
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @veloxts/core@0.6.31
|
|
10
|
+
|
|
11
|
+
## 0.6.30
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- disable source maps for published packages
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @veloxts/core@0.6.30
|
|
18
|
+
|
|
19
|
+
## 0.6.29
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- add multi-tenancy and PostgreSQL support - test and lint fix
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
- @veloxts/core@0.6.29
|
|
26
|
+
|
|
27
|
+
## 0.6.28
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- add multi-tenancy support and postgresql database
|
|
32
|
+
- Updated dependencies
|
|
33
|
+
- @veloxts/core@0.6.28
|
|
34
|
+
|
|
3
35
|
## 0.6.27
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
package/GUIDE.md
CHANGED
|
@@ -43,7 +43,7 @@ const db = new PrismaClient({ adapter });
|
|
|
43
43
|
## Using in Procedures
|
|
44
44
|
|
|
45
45
|
```typescript
|
|
46
|
-
export const userProcedures =
|
|
46
|
+
export const userProcedures = procedures('users', {
|
|
47
47
|
getUser: procedure()
|
|
48
48
|
.input(z.object({ id: z.string().uuid() }))
|
|
49
49
|
.query(async ({ input, ctx }) => {
|
|
@@ -68,6 +68,107 @@ npx prisma migrate deploy # Apply migrations
|
|
|
68
68
|
velox migrate # VeloxTS CLI shortcut
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
## Multi-Tenancy (Schema-per-Tenant)
|
|
72
|
+
|
|
73
|
+
For SaaS applications requiring tenant isolation, import from `@veloxts/orm/tenant`:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import {
|
|
77
|
+
createTenantClientPool,
|
|
78
|
+
createTenantSchemaManager,
|
|
79
|
+
createTenantProvisioner,
|
|
80
|
+
createTenant,
|
|
81
|
+
} from '@veloxts/orm/tenant';
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Setup
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// 1. Schema manager (DDL operations)
|
|
88
|
+
const schemaManager = createTenantSchemaManager({
|
|
89
|
+
databaseUrl: process.env.DATABASE_URL!,
|
|
90
|
+
schemaPrefix: 'tenant_', // PostgreSQL schema prefix
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// 2. Client pool (manages PrismaClient per tenant)
|
|
94
|
+
const clientPool = createTenantClientPool({
|
|
95
|
+
baseDatabaseUrl: process.env.DATABASE_URL!,
|
|
96
|
+
createClient: (schemaName) => {
|
|
97
|
+
const url = `${process.env.DATABASE_URL}?schema=${schemaName}`;
|
|
98
|
+
const adapter = new PrismaPg({ connectionString: url });
|
|
99
|
+
return new PrismaClient({ adapter });
|
|
100
|
+
},
|
|
101
|
+
maxClients: 50, // LRU eviction when exceeded
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// 3. Tenant middleware namespace
|
|
105
|
+
const tenant = createTenant({
|
|
106
|
+
loadTenant: (id) => publicDb.tenant.findUnique({ where: { id } }),
|
|
107
|
+
clientPool,
|
|
108
|
+
publicClient: publicDb, // For shared data in 'public' schema
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Using in Procedures
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const getUsers = procedure()
|
|
116
|
+
.use(auth.requireAuth())
|
|
117
|
+
.use(tenant.middleware()) // Adds ctx.tenant, ctx.db (scoped)
|
|
118
|
+
.query(({ ctx }) => ctx.db.user.findMany());
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The middleware:
|
|
122
|
+
1. Extracts `tenantId` from JWT claims (`ctx.auth.token.tenantId`)
|
|
123
|
+
2. Loads tenant from public schema
|
|
124
|
+
3. Validates tenant status (must be `active`)
|
|
125
|
+
4. Gets tenant-scoped database client from pool
|
|
126
|
+
5. Adds `ctx.tenant`, `ctx.db`, and optionally `ctx.publicDb`
|
|
127
|
+
|
|
128
|
+
### Provisioning Tenants
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const provisioner = createTenantProvisioner({
|
|
132
|
+
schemaManager,
|
|
133
|
+
publicClient: publicDb,
|
|
134
|
+
clientPool,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Create new tenant (creates schema + runs migrations)
|
|
138
|
+
const result = await provisioner.provision({
|
|
139
|
+
slug: 'acme-corp',
|
|
140
|
+
name: 'Acme Corporation',
|
|
141
|
+
});
|
|
142
|
+
// result.tenant.schemaName === 'tenant_acme_corp'
|
|
143
|
+
|
|
144
|
+
// Migrate all tenant schemas
|
|
145
|
+
await provisioner.migrateAll();
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Architecture
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
PostgreSQL Database
|
|
152
|
+
├── public schema (shared)
|
|
153
|
+
│ └── tenants table
|
|
154
|
+
└── tenant_acme_corp schema (isolated)
|
|
155
|
+
├── users
|
|
156
|
+
├── posts
|
|
157
|
+
└── ...
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### JWT Integration
|
|
161
|
+
|
|
162
|
+
Add `tenantId` to your JWT payload when generating tokens:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const tokens = await jwt.generateTokens({
|
|
166
|
+
sub: user.id,
|
|
167
|
+
email: user.email,
|
|
168
|
+
tenantId: user.tenantId, // Include tenant ID
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
71
172
|
## Learn More
|
|
72
173
|
|
|
73
174
|
See [@veloxts/velox](https://www.npmjs.com/package/@veloxts/velox) for complete documentation.
|
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/plugin.d.ts
CHANGED
|
@@ -114,4 +114,3 @@ declare module '@veloxts/core' {
|
|
|
114
114
|
* ```
|
|
115
115
|
*/
|
|
116
116
|
export declare function databasePlugin<TClient extends DatabaseClient>(config: OrmPluginConfig<TClient>): import("@veloxts/core").VeloxPlugin<import("fastify").FastifyPluginOptions>;
|
|
117
|
-
//# sourceMappingURL=plugin.d.ts.map
|
package/dist/plugin.js
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant client pool for managing PrismaClient instances per schema
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - LRU eviction when pool reaches capacity
|
|
6
|
+
* - Idle timeout cleanup
|
|
7
|
+
* - Connection lifecycle management
|
|
8
|
+
*/
|
|
9
|
+
import type { DatabaseClient } from '../types.js';
|
|
10
|
+
import type { TenantClientPool as ITenantClientPool, TenantClientPoolConfig } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Tenant client pool implementation
|
|
13
|
+
*
|
|
14
|
+
* Manages a pool of PrismaClient instances, one per tenant schema.
|
|
15
|
+
* Uses LRU eviction when the pool reaches maximum capacity.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const pool = createTenantClientPool({
|
|
20
|
+
* baseDatabaseUrl: process.env.DATABASE_URL!,
|
|
21
|
+
* createClient: (schemaName) => {
|
|
22
|
+
* const url = `${process.env.DATABASE_URL}?schema=${schemaName}`;
|
|
23
|
+
* const adapter = new PrismaPg({ connectionString: url });
|
|
24
|
+
* return new PrismaClient({ adapter });
|
|
25
|
+
* },
|
|
26
|
+
* maxClients: 50,
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* const client = await pool.getClient('tenant_acme');
|
|
30
|
+
* // Use client...
|
|
31
|
+
* pool.releaseClient('tenant_acme');
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function createTenantClientPool<TClient extends DatabaseClient>(config: TenantClientPoolConfig<TClient>): ITenantClientPool<TClient>;
|
|
35
|
+
/**
|
|
36
|
+
* Type alias for the client pool
|
|
37
|
+
*/
|
|
38
|
+
export type { ITenantClientPool as TenantClientPool };
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant client pool for managing PrismaClient instances per schema
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - LRU eviction when pool reaches capacity
|
|
6
|
+
* - Idle timeout cleanup
|
|
7
|
+
* - Connection lifecycle management
|
|
8
|
+
*/
|
|
9
|
+
import { ClientCreateError, ClientDisconnectError, ClientPoolExhaustedError } from './errors.js';
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration values
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULTS = {
|
|
14
|
+
maxClients: 50,
|
|
15
|
+
idleTimeoutMs: 5 * 60 * 1000, // 5 minutes
|
|
16
|
+
cleanupIntervalMs: 60 * 1000, // 1 minute
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Tenant client pool implementation
|
|
20
|
+
*
|
|
21
|
+
* Manages a pool of PrismaClient instances, one per tenant schema.
|
|
22
|
+
* Uses LRU eviction when the pool reaches maximum capacity.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const pool = createTenantClientPool({
|
|
27
|
+
* baseDatabaseUrl: process.env.DATABASE_URL!,
|
|
28
|
+
* createClient: (schemaName) => {
|
|
29
|
+
* const url = `${process.env.DATABASE_URL}?schema=${schemaName}`;
|
|
30
|
+
* const adapter = new PrismaPg({ connectionString: url });
|
|
31
|
+
* return new PrismaClient({ adapter });
|
|
32
|
+
* },
|
|
33
|
+
* maxClients: 50,
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* const client = await pool.getClient('tenant_acme');
|
|
37
|
+
* // Use client...
|
|
38
|
+
* pool.releaseClient('tenant_acme');
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function createTenantClientPool(config) {
|
|
42
|
+
const maxClients = config.maxClients ?? DEFAULTS.maxClients;
|
|
43
|
+
const idleTimeoutMs = config.idleTimeoutMs ?? DEFAULTS.idleTimeoutMs;
|
|
44
|
+
// Pool state
|
|
45
|
+
const clients = new Map();
|
|
46
|
+
let totalCreated = 0;
|
|
47
|
+
let totalEvicted = 0;
|
|
48
|
+
let cleanupTimer = null;
|
|
49
|
+
/**
|
|
50
|
+
* Start the idle cleanup timer
|
|
51
|
+
*/
|
|
52
|
+
function startCleanupTimer() {
|
|
53
|
+
if (cleanupTimer)
|
|
54
|
+
return;
|
|
55
|
+
cleanupTimer = setInterval(() => {
|
|
56
|
+
void cleanupIdleClients();
|
|
57
|
+
}, DEFAULTS.cleanupIntervalMs);
|
|
58
|
+
// Don't block process exit
|
|
59
|
+
if (cleanupTimer.unref) {
|
|
60
|
+
cleanupTimer.unref();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Stop the cleanup timer
|
|
65
|
+
*/
|
|
66
|
+
function stopCleanupTimer() {
|
|
67
|
+
if (cleanupTimer) {
|
|
68
|
+
clearInterval(cleanupTimer);
|
|
69
|
+
cleanupTimer = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Cleanup clients that have been idle too long
|
|
74
|
+
*/
|
|
75
|
+
async function cleanupIdleClients() {
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
const toEvict = [];
|
|
78
|
+
for (const [schemaName, cached] of clients) {
|
|
79
|
+
if (now - cached.lastAccessedAt > idleTimeoutMs) {
|
|
80
|
+
toEvict.push(schemaName);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
for (const schemaName of toEvict) {
|
|
84
|
+
await evictClient(schemaName);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Evict a client from the pool
|
|
89
|
+
*/
|
|
90
|
+
async function evictClient(schemaName) {
|
|
91
|
+
const cached = clients.get(schemaName);
|
|
92
|
+
if (!cached)
|
|
93
|
+
return;
|
|
94
|
+
clients.delete(schemaName);
|
|
95
|
+
totalEvicted++;
|
|
96
|
+
try {
|
|
97
|
+
await cached.client.$disconnect();
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
// Log but don't throw - eviction should be best-effort
|
|
101
|
+
console.warn(`[TenantClientPool] Failed to disconnect client for ${schemaName}:`, error);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Find and evict the least recently used client
|
|
106
|
+
*/
|
|
107
|
+
async function evictLRU() {
|
|
108
|
+
let oldest = null;
|
|
109
|
+
for (const [schemaName, cached] of clients) {
|
|
110
|
+
if (!oldest || cached.lastAccessedAt < oldest.lastAccessedAt) {
|
|
111
|
+
oldest = { schemaName, lastAccessedAt: cached.lastAccessedAt };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (oldest) {
|
|
115
|
+
await evictClient(oldest.schemaName);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create a new client for a schema
|
|
120
|
+
*/
|
|
121
|
+
async function createClient(schemaName) {
|
|
122
|
+
try {
|
|
123
|
+
const client = config.createClient(schemaName);
|
|
124
|
+
// Connect the client
|
|
125
|
+
await client.$connect();
|
|
126
|
+
return client;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
throw new ClientCreateError(schemaName, error instanceof Error ? error : new Error(String(error)));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Start cleanup timer
|
|
133
|
+
startCleanupTimer();
|
|
134
|
+
return {
|
|
135
|
+
/**
|
|
136
|
+
* Get or create a client for a tenant schema
|
|
137
|
+
*/
|
|
138
|
+
async getClient(schemaName) {
|
|
139
|
+
// Check if client exists in pool
|
|
140
|
+
const cached = clients.get(schemaName);
|
|
141
|
+
if (cached) {
|
|
142
|
+
// Update last accessed time (LRU tracking)
|
|
143
|
+
cached.lastAccessedAt = Date.now();
|
|
144
|
+
return cached.client;
|
|
145
|
+
}
|
|
146
|
+
// Check if pool is at capacity
|
|
147
|
+
if (clients.size >= maxClients) {
|
|
148
|
+
// Try to evict idle clients first
|
|
149
|
+
await cleanupIdleClients();
|
|
150
|
+
// If still at capacity, evict LRU
|
|
151
|
+
if (clients.size >= maxClients) {
|
|
152
|
+
await evictLRU();
|
|
153
|
+
}
|
|
154
|
+
// If still at capacity (shouldn't happen), throw
|
|
155
|
+
if (clients.size >= maxClients) {
|
|
156
|
+
throw new ClientPoolExhaustedError(maxClients);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Create new client
|
|
160
|
+
const client = await createClient(schemaName);
|
|
161
|
+
const now = Date.now();
|
|
162
|
+
clients.set(schemaName, {
|
|
163
|
+
client,
|
|
164
|
+
schemaName,
|
|
165
|
+
lastAccessedAt: now,
|
|
166
|
+
createdAt: now,
|
|
167
|
+
});
|
|
168
|
+
totalCreated++;
|
|
169
|
+
return client;
|
|
170
|
+
},
|
|
171
|
+
/**
|
|
172
|
+
* Release a client back to the pool
|
|
173
|
+
*
|
|
174
|
+
* Note: This doesn't actually remove the client, it just marks
|
|
175
|
+
* it as available for LRU eviction if needed.
|
|
176
|
+
*/
|
|
177
|
+
releaseClient(schemaName) {
|
|
178
|
+
const cached = clients.get(schemaName);
|
|
179
|
+
if (cached) {
|
|
180
|
+
cached.lastAccessedAt = Date.now();
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
/**
|
|
184
|
+
* Check if a client exists in the pool without creating it
|
|
185
|
+
* Useful for health checks
|
|
186
|
+
*/
|
|
187
|
+
hasClient(schemaName) {
|
|
188
|
+
return clients.has(schemaName);
|
|
189
|
+
},
|
|
190
|
+
/**
|
|
191
|
+
* Stop the cleanup timer without disconnecting clients
|
|
192
|
+
*
|
|
193
|
+
* Use this when you need to stop the timer but keep clients connected.
|
|
194
|
+
* For full cleanup, use `disconnectAll()` instead.
|
|
195
|
+
*/
|
|
196
|
+
close() {
|
|
197
|
+
stopCleanupTimer();
|
|
198
|
+
},
|
|
199
|
+
/**
|
|
200
|
+
* Disconnect all clients and clear the pool
|
|
201
|
+
*
|
|
202
|
+
* IMPORTANT: This also stops the cleanup timer.
|
|
203
|
+
* Always call this method during application shutdown.
|
|
204
|
+
*/
|
|
205
|
+
async disconnectAll() {
|
|
206
|
+
stopCleanupTimer();
|
|
207
|
+
const errors = [];
|
|
208
|
+
for (const [schemaName, cached] of clients) {
|
|
209
|
+
try {
|
|
210
|
+
await cached.client.$disconnect();
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
errors.push(new ClientDisconnectError(schemaName, error instanceof Error ? error : new Error(String(error))));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
clients.clear();
|
|
217
|
+
if (errors.length > 0) {
|
|
218
|
+
throw new AggregateError(errors, 'Failed to disconnect some clients');
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
/**
|
|
222
|
+
* Get current pool statistics
|
|
223
|
+
*/
|
|
224
|
+
getStats() {
|
|
225
|
+
return {
|
|
226
|
+
activeClients: clients.size,
|
|
227
|
+
maxClients,
|
|
228
|
+
totalCreated,
|
|
229
|
+
totalEvicted,
|
|
230
|
+
};
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant-specific error classes for @veloxts/orm/tenant
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for tenant-related errors
|
|
6
|
+
*/
|
|
7
|
+
export declare class TenantError extends Error {
|
|
8
|
+
readonly code: TenantErrorCode;
|
|
9
|
+
readonly tenantId?: string;
|
|
10
|
+
readonly schemaName?: string;
|
|
11
|
+
constructor(message: string, code: TenantErrorCode, options?: {
|
|
12
|
+
tenantId?: string;
|
|
13
|
+
schemaName?: string;
|
|
14
|
+
cause?: Error;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Error codes for tenant operations
|
|
19
|
+
*/
|
|
20
|
+
export type TenantErrorCode = 'TENANT_NOT_FOUND' | 'TENANT_SUSPENDED' | 'TENANT_PENDING' | 'TENANT_MIGRATING' | 'TENANT_ID_MISSING' | 'TENANT_ACCESS_DENIED' | 'SCHEMA_CREATE_FAILED' | 'SCHEMA_DELETE_FAILED' | 'SCHEMA_MIGRATE_FAILED' | 'SCHEMA_NOT_FOUND' | 'SCHEMA_LIST_FAILED' | 'SCHEMA_ALREADY_EXISTS' | 'CLIENT_POOL_EXHAUSTED' | 'CLIENT_CREATE_FAILED' | 'CLIENT_DISCONNECT_FAILED' | 'INVALID_SLUG' | 'PROVISION_FAILED' | 'DEPROVISION_FAILED';
|
|
21
|
+
/**
|
|
22
|
+
* Tenant not found in database
|
|
23
|
+
*/
|
|
24
|
+
export declare class TenantNotFoundError extends TenantError {
|
|
25
|
+
constructor(tenantId: string);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Tenant is suspended and cannot be accessed
|
|
29
|
+
*/
|
|
30
|
+
export declare class TenantSuspendedError extends TenantError {
|
|
31
|
+
constructor(tenantId: string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Tenant is pending activation
|
|
35
|
+
*/
|
|
36
|
+
export declare class TenantPendingError extends TenantError {
|
|
37
|
+
constructor(tenantId: string);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Tenant is currently being migrated
|
|
41
|
+
*/
|
|
42
|
+
export declare class TenantMigratingError extends TenantError {
|
|
43
|
+
constructor(tenantId: string);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Tenant ID missing from request context
|
|
47
|
+
*/
|
|
48
|
+
export declare class TenantIdMissingError extends TenantError {
|
|
49
|
+
constructor();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* User does not have access to the requested tenant
|
|
53
|
+
*
|
|
54
|
+
* SECURITY: This error is thrown when tenant access verification fails.
|
|
55
|
+
* It prevents tenant isolation bypass attacks where a user might try
|
|
56
|
+
* to access a tenant they don't belong to by manipulating JWT claims.
|
|
57
|
+
*/
|
|
58
|
+
export declare class TenantAccessDeniedError extends TenantError {
|
|
59
|
+
readonly userId?: string;
|
|
60
|
+
constructor(tenantId: string, userId?: string);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Schema creation failed
|
|
64
|
+
*/
|
|
65
|
+
export declare class SchemaCreateError extends TenantError {
|
|
66
|
+
constructor(schemaName: string, cause?: Error);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Schema deletion failed
|
|
70
|
+
*/
|
|
71
|
+
export declare class SchemaDeleteError extends TenantError {
|
|
72
|
+
constructor(schemaName: string, cause?: Error);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Schema migration failed
|
|
76
|
+
*/
|
|
77
|
+
export declare class SchemaMigrateError extends TenantError {
|
|
78
|
+
constructor(schemaName: string, cause?: Error);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Schema not found
|
|
82
|
+
*/
|
|
83
|
+
export declare class SchemaNotFoundError extends TenantError {
|
|
84
|
+
constructor(schemaName: string);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Schema list operation failed
|
|
88
|
+
*/
|
|
89
|
+
export declare class SchemaListError extends TenantError {
|
|
90
|
+
constructor(cause?: Error);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Schema already exists
|
|
94
|
+
*/
|
|
95
|
+
export declare class SchemaAlreadyExistsError extends TenantError {
|
|
96
|
+
constructor(schemaName: string);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Client pool has reached maximum capacity
|
|
100
|
+
*/
|
|
101
|
+
export declare class ClientPoolExhaustedError extends TenantError {
|
|
102
|
+
constructor(maxClients: number);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Failed to create database client
|
|
106
|
+
*/
|
|
107
|
+
export declare class ClientCreateError extends TenantError {
|
|
108
|
+
constructor(schemaName: string, cause?: Error);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Failed to disconnect database client
|
|
112
|
+
*/
|
|
113
|
+
export declare class ClientDisconnectError extends TenantError {
|
|
114
|
+
constructor(schemaName: string, cause?: Error);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Invalid tenant slug format
|
|
118
|
+
*/
|
|
119
|
+
export declare class InvalidSlugError extends TenantError {
|
|
120
|
+
constructor(slug: string, reason: string);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Tenant provisioning failed
|
|
124
|
+
*/
|
|
125
|
+
export declare class ProvisionError extends TenantError {
|
|
126
|
+
constructor(slug: string, cause?: Error);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Tenant deprovisioning failed
|
|
130
|
+
*/
|
|
131
|
+
export declare class DeprovisionError extends TenantError {
|
|
132
|
+
constructor(tenantId: string, cause?: Error);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Type guard to check if an error is a TenantError
|
|
136
|
+
*/
|
|
137
|
+
export declare function isTenantError(error: unknown): error is TenantError;
|
|
138
|
+
/**
|
|
139
|
+
* Get error based on tenant status
|
|
140
|
+
*/
|
|
141
|
+
export declare function getTenantStatusError(tenantId: string, status: string): TenantError | null;
|