@veloxts/orm 0.6.27 → 0.6.29

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,"file":"provisioner.js","sourceRoot":"","sources":["../../../src/tenant/schema/provisioner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,432 @@
1
+ /**
2
+ * Multi-tenancy type definitions for @veloxts/orm/tenant
3
+ *
4
+ * Schema-per-tenant isolation with PostgreSQL schemas.
5
+ */
6
+ import type { DatabaseClient } from '../types.js';
7
+ /**
8
+ * Tenant status lifecycle states
9
+ */
10
+ export type TenantStatus = 'active' | 'suspended' | 'pending' | 'migrating';
11
+ /**
12
+ * Tenant entity representing a single tenant in the system
13
+ */
14
+ export interface Tenant {
15
+ /** Unique tenant identifier (UUID) */
16
+ id: string;
17
+ /** URL-safe slug for the tenant (e.g., 'acme-corp') */
18
+ slug: string;
19
+ /** Human-readable tenant name */
20
+ name: string;
21
+ /** PostgreSQL schema name (e.g., 'tenant_acme_corp') */
22
+ schemaName: string;
23
+ /** Current tenant status */
24
+ status: TenantStatus;
25
+ /** ISO timestamp when tenant was created */
26
+ createdAt: Date;
27
+ /** ISO timestamp when tenant was last updated */
28
+ updatedAt: Date;
29
+ }
30
+ /**
31
+ * Configuration for tenant client pool
32
+ */
33
+ export interface TenantClientPoolConfig<TClient extends DatabaseClient> {
34
+ /**
35
+ * Base database URL (without schema parameter)
36
+ * @example 'postgresql://user:pass@localhost:5432/mydb'
37
+ */
38
+ baseDatabaseUrl: string;
39
+ /**
40
+ * Factory function to create a new PrismaClient for a tenant schema
41
+ *
42
+ * @param schemaName - The PostgreSQL schema name to connect to
43
+ * @returns A new PrismaClient instance configured for the schema
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * createClient: (schemaName) => {
48
+ * const url = `${baseUrl}?schema=${schemaName}`;
49
+ * const adapter = new PrismaPg({ connectionString: url });
50
+ * return new PrismaClient({ adapter });
51
+ * }
52
+ * ```
53
+ */
54
+ createClient: (schemaName: string) => TClient;
55
+ /**
56
+ * Maximum number of concurrent clients in the pool
57
+ * @default 50
58
+ */
59
+ maxClients?: number;
60
+ /**
61
+ * Idle timeout in milliseconds before evicting unused clients
62
+ * @default 300000 (5 minutes)
63
+ */
64
+ idleTimeoutMs?: number;
65
+ }
66
+ /**
67
+ * Cached client entry with metadata
68
+ */
69
+ export interface CachedClient<TClient extends DatabaseClient> {
70
+ /** The database client instance */
71
+ client: TClient;
72
+ /** Schema this client is connected to */
73
+ schemaName: string;
74
+ /** Timestamp when client was last accessed */
75
+ lastAccessedAt: number;
76
+ /** Timestamp when client was created */
77
+ createdAt: number;
78
+ }
79
+ /**
80
+ * Configuration for tenant middleware
81
+ */
82
+ export interface TenantMiddlewareConfig<TClient extends DatabaseClient> {
83
+ /**
84
+ * Function to load tenant from public schema by ID
85
+ *
86
+ * @param tenantId - The tenant ID from JWT claim
87
+ * @returns The tenant entity or null if not found
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * loadTenant: async (tenantId) => {
92
+ * return publicDb.tenant.findUnique({ where: { id: tenantId } });
93
+ * }
94
+ * ```
95
+ */
96
+ loadTenant: (tenantId: string) => Promise<Tenant | null>;
97
+ /**
98
+ * Client pool for obtaining tenant-scoped database clients
99
+ */
100
+ clientPool: TenantClientPool<TClient>;
101
+ /**
102
+ * Optional: Public database client for shared data
103
+ * If provided, will be available as ctx.publicDb
104
+ */
105
+ publicClient?: TClient;
106
+ /**
107
+ * Extract tenant ID from context
108
+ * @default Extracts from ctx.auth.token.tenantId (JWT claim)
109
+ */
110
+ getTenantId?: (ctx: TenantContextInput) => string | undefined;
111
+ /**
112
+ * Allow requests without tenant context
113
+ * Useful for public endpoints that don't require tenant isolation
114
+ * @default false
115
+ */
116
+ allowNoTenant?: boolean;
117
+ /**
118
+ * SECURITY: Verify user has access to the requested tenant
119
+ *
120
+ * This callback is called AFTER the tenant is loaded but BEFORE
121
+ * granting access. Use it to verify the user actually belongs
122
+ * to the tenant they're trying to access.
123
+ *
124
+ * This prevents tenant isolation bypass attacks where a user
125
+ * might manipulate JWT claims to access another tenant's data.
126
+ *
127
+ * @param ctx - The request context containing user info
128
+ * @param tenant - The loaded tenant entity
129
+ * @returns true if access is allowed, false to deny
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * verifyTenantAccess: async (ctx, tenant) => {
134
+ * // Check user's tenant memberships in database
135
+ * const membership = await publicDb.tenantMember.findFirst({
136
+ * where: { userId: ctx.user?.id, tenantId: tenant.id }
137
+ * });
138
+ * return membership !== null;
139
+ * }
140
+ * ```
141
+ */
142
+ verifyTenantAccess?: (ctx: TenantContextInput, tenant: Tenant) => Promise<boolean> | boolean;
143
+ }
144
+ /**
145
+ * Input context for tenant middleware (before tenant is resolved)
146
+ */
147
+ export interface TenantContextInput {
148
+ /** User from auth middleware */
149
+ user?: {
150
+ id: string;
151
+ [key: string]: unknown;
152
+ };
153
+ /** Auth context with JWT token */
154
+ auth?: {
155
+ token?: {
156
+ tenantId?: string;
157
+ [key: string]: unknown;
158
+ };
159
+ [key: string]: unknown;
160
+ };
161
+ [key: string]: unknown;
162
+ }
163
+ /**
164
+ * Context extension added by tenant middleware
165
+ */
166
+ export interface TenantContext<TClient extends DatabaseClient> {
167
+ /** Current tenant info */
168
+ tenant: Tenant;
169
+ /** Tenant-scoped database client */
170
+ db: TClient;
171
+ /** Public schema client (if configured) */
172
+ publicDb?: TClient;
173
+ }
174
+ /**
175
+ * Configuration for tenant schema manager
176
+ */
177
+ export interface TenantSchemaManagerConfig {
178
+ /**
179
+ * Database URL for executing schema DDL
180
+ */
181
+ databaseUrl: string;
182
+ /**
183
+ * Prefix for tenant schema names
184
+ * @default 'tenant_'
185
+ */
186
+ schemaPrefix?: string;
187
+ /**
188
+ * Path to Prisma schema file for migrations
189
+ * @default './prisma/schema.prisma'
190
+ */
191
+ prismaSchemaPath?: string;
192
+ }
193
+ /**
194
+ * Result of schema creation
195
+ */
196
+ export interface SchemaCreateResult {
197
+ /** The created schema name */
198
+ schemaName: string;
199
+ /** Whether the schema was newly created (false if already existed) */
200
+ created: boolean;
201
+ }
202
+ /**
203
+ * Result of schema migration
204
+ */
205
+ export interface SchemaMigrateResult {
206
+ /** The migrated schema name */
207
+ schemaName: string;
208
+ /** Number of migrations applied */
209
+ migrationsApplied: number;
210
+ }
211
+ /**
212
+ * Extended database client interface for tenant operations
213
+ *
214
+ * This interface defines the Prisma-specific methods needed by the provisioner.
215
+ * It allows type-safe access to tenant CRUD operations without unsafe inline casting.
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * // Your Prisma client already satisfies this interface if you have a 'tenant' model
220
+ * const provisioner = createTenantProvisioner({
221
+ * schemaManager,
222
+ * publicClient: prismaClient as TenantDatabaseClient,
223
+ * clientPool,
224
+ * });
225
+ * ```
226
+ */
227
+ export interface TenantDatabaseClient extends DatabaseClient {
228
+ /**
229
+ * Prisma model delegate for tenant operations (optional)
230
+ * If not available, falls back to raw queries
231
+ */
232
+ tenant?: {
233
+ findUnique: (args: {
234
+ where: {
235
+ id?: string;
236
+ slug?: string;
237
+ };
238
+ }) => Promise<Tenant | null>;
239
+ findMany: (args?: {
240
+ where?: {
241
+ status?: TenantStatus;
242
+ };
243
+ }) => Promise<Tenant[]>;
244
+ create: (args: {
245
+ data: {
246
+ slug: string;
247
+ name: string;
248
+ schemaName: string;
249
+ status: TenantStatus;
250
+ };
251
+ }) => Promise<Tenant>;
252
+ update: (args: {
253
+ where: {
254
+ id: string;
255
+ };
256
+ data: {
257
+ status?: TenantStatus;
258
+ updatedAt?: Date;
259
+ };
260
+ }) => Promise<Tenant>;
261
+ delete: (args: {
262
+ where: {
263
+ id: string;
264
+ };
265
+ }) => Promise<Tenant>;
266
+ };
267
+ /**
268
+ * Prisma raw query execution (fallback when model delegate unavailable)
269
+ */
270
+ $queryRaw?: <T>(query: TemplateStringsArray, ...values: unknown[]) => Promise<T[]>;
271
+ /**
272
+ * Prisma raw execute for INSERT/UPDATE/DELETE
273
+ */
274
+ $executeRaw?: (query: TemplateStringsArray, ...values: unknown[]) => Promise<number>;
275
+ }
276
+ /**
277
+ * Configuration for tenant provisioner
278
+ */
279
+ export interface TenantProvisionerConfig<TClient extends DatabaseClient> {
280
+ /** Schema manager for DDL operations */
281
+ schemaManager: TenantSchemaManager;
282
+ /**
283
+ * Public schema client for creating tenant records
284
+ *
285
+ * Must implement TenantDatabaseClient interface with either:
286
+ * - `tenant` model delegate (Prisma with tenant model)
287
+ * - `$queryRaw` and `$executeRaw` methods (raw query fallback)
288
+ */
289
+ publicClient: TClient & Partial<TenantDatabaseClient>;
290
+ /** Client pool for testing new tenant connections */
291
+ clientPool: TenantClientPool<TClient>;
292
+ }
293
+ /**
294
+ * Input for provisioning a new tenant
295
+ */
296
+ export interface TenantProvisionInput {
297
+ /** URL-safe slug (will be sanitized) */
298
+ slug: string;
299
+ /** Human-readable name */
300
+ name: string;
301
+ /** Optional: Additional metadata */
302
+ metadata?: Record<string, unknown>;
303
+ }
304
+ /**
305
+ * Result of tenant provisioning
306
+ */
307
+ export interface TenantProvisionResult {
308
+ /** The created tenant */
309
+ tenant: Tenant;
310
+ /** Whether schema was newly created */
311
+ schemaCreated: boolean;
312
+ /** Number of migrations applied */
313
+ migrationsApplied: number;
314
+ }
315
+ /**
316
+ * Interface for tenant client pool
317
+ */
318
+ export interface TenantClientPool<TClient extends DatabaseClient> {
319
+ /**
320
+ * Get or create a client for a tenant schema
321
+ */
322
+ getClient(schemaName: string): Promise<TClient>;
323
+ /**
324
+ * Release a client back to the pool
325
+ */
326
+ releaseClient(schemaName: string): void;
327
+ /**
328
+ * Check if a client exists in the pool without creating it
329
+ * Useful for health checks
330
+ */
331
+ hasClient(schemaName: string): boolean;
332
+ /**
333
+ * Disconnect all clients and clear the pool
334
+ *
335
+ * IMPORTANT: This also stops the cleanup timer.
336
+ * Always call this method during application shutdown.
337
+ */
338
+ disconnectAll(): Promise<void>;
339
+ /**
340
+ * Stop the cleanup timer without disconnecting clients
341
+ *
342
+ * Use this when you need to stop the timer but keep clients connected.
343
+ * For full cleanup, use `disconnectAll()` instead.
344
+ */
345
+ close(): void;
346
+ /**
347
+ * Get current pool statistics
348
+ */
349
+ getStats(): TenantPoolStats;
350
+ }
351
+ /**
352
+ * Pool statistics
353
+ */
354
+ export interface TenantPoolStats {
355
+ /** Number of active clients */
356
+ activeClients: number;
357
+ /** Maximum allowed clients */
358
+ maxClients: number;
359
+ /** Total clients created since pool initialization */
360
+ totalCreated: number;
361
+ /** Total clients evicted due to idle timeout */
362
+ totalEvicted: number;
363
+ }
364
+ /**
365
+ * Interface for tenant schema manager
366
+ */
367
+ export interface TenantSchemaManager {
368
+ /**
369
+ * Create a new PostgreSQL schema
370
+ */
371
+ createSchema(slug: string): Promise<SchemaCreateResult>;
372
+ /**
373
+ * Run Prisma migrations on a schema
374
+ */
375
+ migrateSchema(schemaName: string): Promise<SchemaMigrateResult>;
376
+ /**
377
+ * Delete a schema (DANGEROUS - drops all data)
378
+ */
379
+ deleteSchema(schemaName: string): Promise<void>;
380
+ /**
381
+ * List all tenant schemas
382
+ */
383
+ listSchemas(): Promise<string[]>;
384
+ /**
385
+ * Check if a schema exists
386
+ */
387
+ schemaExists(schemaName: string): Promise<boolean>;
388
+ }
389
+ /**
390
+ * Interface for tenant provisioner
391
+ */
392
+ export interface TenantProvisioner {
393
+ /**
394
+ * Provision a new tenant (create record + schema + migrate)
395
+ */
396
+ provision(input: TenantProvisionInput): Promise<TenantProvisionResult>;
397
+ /**
398
+ * Deprovision a tenant (delete schema + record)
399
+ */
400
+ deprovision(tenantId: string): Promise<void>;
401
+ /**
402
+ * Migrate all tenant schemas
403
+ */
404
+ migrateAll(): Promise<SchemaMigrateResult[]>;
405
+ }
406
+ /**
407
+ * Extend @veloxts/core BaseContext with tenant fields
408
+ *
409
+ * Users should add this to their project:
410
+ * ```typescript
411
+ * declare module '@veloxts/core' {
412
+ * interface BaseContext {
413
+ * tenant?: Tenant;
414
+ * db: PrismaClient;
415
+ * publicDb?: PrismaClient;
416
+ * }
417
+ * }
418
+ * ```
419
+ */
420
+ /**
421
+ * Extend @veloxts/auth TokenPayload with tenantId
422
+ *
423
+ * Users should add this to their project:
424
+ * ```typescript
425
+ * declare module '@veloxts/auth' {
426
+ * interface TokenPayload {
427
+ * tenantId?: string;
428
+ * }
429
+ * }
430
+ * ```
431
+ */
432
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tenant/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Multi-tenancy type definitions for @veloxts/orm/tenant
3
+ *
4
+ * Schema-per-tenant isolation with PostgreSQL schemas.
5
+ */
6
+ export {};
7
+ // ============================================================================
8
+ // Declaration Merging
9
+ // ============================================================================
10
+ /**
11
+ * Extend @veloxts/core BaseContext with tenant fields
12
+ *
13
+ * Users should add this to their project:
14
+ * ```typescript
15
+ * declare module '@veloxts/core' {
16
+ * interface BaseContext {
17
+ * tenant?: Tenant;
18
+ * db: PrismaClient;
19
+ * publicDb?: PrismaClient;
20
+ * }
21
+ * }
22
+ * ```
23
+ */
24
+ /**
25
+ * Extend @veloxts/auth TokenPayload with tenantId
26
+ *
27
+ * Users should add this to their project:
28
+ * ```typescript
29
+ * declare module '@veloxts/auth' {
30
+ * interface TokenPayload {
31
+ * tenantId?: string;
32
+ * }
33
+ * }
34
+ * ```
35
+ */
36
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tenant/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;AA4bH,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;GAWG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veloxts/orm",
3
- "version": "0.6.27",
3
+ "version": "0.6.29",
4
4
  "description": "Prisma wrapper with enhanced DX for VeloxTS framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -9,13 +9,21 @@
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
12
+ },
13
+ "./tenant": {
14
+ "types": "./dist/tenant/index.d.ts",
15
+ "import": "./dist/tenant/index.js"
12
16
  }
13
17
  },
14
18
  "dependencies": {
15
19
  "fastify": "5.6.2",
16
- "@veloxts/core": "0.6.27"
20
+ "pg": "8.16.0",
21
+ "pg-format": "1.0.4",
22
+ "@veloxts/core": "0.6.29"
17
23
  },
18
24
  "devDependencies": {
25
+ "@types/pg": "8.15.4",
26
+ "@types/pg-format": "1.0.5",
19
27
  "@vitest/coverage-v8": "4.0.16",
20
28
  "typescript": "5.9.3",
21
29
  "vitest": "4.0.16"