@vritti/api-sdk 0.0.1 → 0.0.3

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/dist/index.d.cts CHANGED
@@ -1,3 +1,756 @@
1
- declare const getHello: () => string;
1
+ import * as _nestjs_common from '@nestjs/common';
2
+ import { DynamicModule, OnModuleDestroy, OnModuleInit, CanActivate, ExecutionContext } from '@nestjs/common';
3
+ import { ConfigService } from '@nestjs/config';
4
+ import { Reflector } from '@nestjs/core';
5
+ import { JwtService } from '@nestjs/jwt';
6
+ import { FastifyRequest } from 'fastify';
2
7
 
3
- export { getHello };
8
+ /**
9
+ * Global authentication configuration module
10
+ *
11
+ * This module provides:
12
+ * - JWT token verification (JwtModule)
13
+ * - Global authentication guard (VrittiAuthGuard)
14
+ * - Support for @Public and @Onboarding decorators
15
+ *
16
+ * ## Features:
17
+ * - Automatically applies VrittiAuthGuard to all routes
18
+ * - Configures JwtModule with JWT_SECRET from environment
19
+ * - Exports JwtModule for token generation in services
20
+ *
21
+ * ## Usage in Application:
22
+ *
23
+ * @example
24
+ * // In app.module.ts
25
+ * @Module({
26
+ * imports: [
27
+ * ConfigModule.forRoot({ isGlobal: true }),
28
+ *
29
+ * // Auth configuration (global guard + JWT)
30
+ * AuthConfigModule.forRootAsync(),
31
+ *
32
+ * // Database configuration (Gateway mode)
33
+ * DatabaseModule.forServer({
34
+ * useFactory: (config: ConfigService) => ({
35
+ * primaryDb: {
36
+ * host: config.get('PRIMARY_DB_HOST'),
37
+ * // ... other config
38
+ * },
39
+ * prismaClientConstructor: PrismaClient,
40
+ * }),
41
+ * inject: [ConfigService],
42
+ * }),
43
+ * ],
44
+ * })
45
+ * export class AppModule {}
46
+ *
47
+ * ## Environment Variables Required:
48
+ * - JWT_SECRET: Secret key to verify access tokens (required)
49
+ * - JWT_REFRESH_SECRET: Secret key for refresh tokens (optional, falls back to JWT_SECRET)
50
+ *
51
+ * ## Bypass Authentication:
52
+ *
53
+ * @example
54
+ * // Skip authentication on specific endpoints
55
+ * @Public()
56
+ * @Post('auth/login')
57
+ * async login() { ... }
58
+ *
59
+ * @example
60
+ * // Onboarding endpoints (only accept onboarding tokens)
61
+ * @Onboarding()
62
+ * @Post('onboarding/verify-email')
63
+ * async verifyEmail(@Request() req) {
64
+ * const userId = req.user.id; // Available from guard
65
+ * ...
66
+ * }
67
+ */
68
+ declare class AuthConfigModule {
69
+ /**
70
+ * Register the auth module with async configuration
71
+ *
72
+ * This method:
73
+ * 1. Configures JwtModule with JWT_SECRET from ConfigService
74
+ * 2. Provides VrittiAuthGuard globally (applies to all routes)
75
+ * 3. Exports JwtModule for use in other modules (e.g., for signing tokens)
76
+ *
77
+ * @returns Dynamic module configuration
78
+ */
79
+ static forRootAsync(): DynamicModule;
80
+ }
81
+
82
+ /**
83
+ * Primary database connection configuration
84
+ */
85
+ interface PrimaryDbConfig {
86
+ /** Database host */
87
+ host: string;
88
+ /** Database port (default: 5432) */
89
+ port?: number;
90
+ /** Database username */
91
+ username: string;
92
+ /** Database password */
93
+ password: string;
94
+ /** Database name */
95
+ database: string;
96
+ /** Default schema (default: 'public') */
97
+ schema?: string;
98
+ /** SSL mode: 'require' | 'prefer' | 'disable' (default: 'require') */
99
+ sslMode?: 'require' | 'prefer' | 'disable';
100
+ }
101
+ /**
102
+ * Configuration options for DatabaseModule
103
+ */
104
+ interface DatabaseModuleOptions {
105
+ /**
106
+ * Primary database configuration (for tenant registry queries)
107
+ * Only required in gateway mode
108
+ * @example
109
+ * primaryDb: {
110
+ * host: 'aws-pooler.supabase.com',
111
+ * port: 5432,
112
+ * username: 'postgres.xxx',
113
+ * password: 'xxx',
114
+ * database: 'postgres',
115
+ * schema: 'public',
116
+ * sslMode: 'require',
117
+ * }
118
+ */
119
+ primaryDb: PrimaryDbConfig;
120
+ /**
121
+ * Primary database client constructor (for querying tenant registry)
122
+ * Only required in gateway mode
123
+ * @example import { PrismaClient } from '@prisma/client'
124
+ */
125
+ prismaClientConstructor: any;
126
+ /**
127
+ * Connection cache TTL in milliseconds
128
+ * Idle connections will be closed after this period
129
+ * @default 300000 (5 minutes)
130
+ */
131
+ connectionCacheTTL?: number;
132
+ /**
133
+ * Maximum number of concurrent connections per tenant
134
+ * @default 10
135
+ */
136
+ maxConnections?: number;
137
+ /**
138
+ * Encryption key for decrypting database credentials
139
+ * Required if tenant config stores encrypted passwords
140
+ */
141
+ encryptionKey?: string;
142
+ }
143
+
144
+ /**
145
+ * Tenant configuration stored in cloud database
146
+ * This is the shape of data returned from the tenant registry
147
+ *
148
+ * Note: Database configuration is now stored in a separate TenantDatabaseConfig table
149
+ * but is flattened into this interface for convenience.
150
+ */
151
+ interface TenantInfo {
152
+ /** Unique tenant identifier */
153
+ id: string;
154
+ /** Human-readable tenant slug */
155
+ subdomain: string;
156
+ /** Tenant type - SHARED or DEDICATED */
157
+ type: 'SHARED' | 'DEDICATED';
158
+ /** Tenant status */
159
+ status: string;
160
+ /** For SHARED tenants: schema name within the shared database */
161
+ schemaName?: string;
162
+ /** For DEDICATED tenants: database configuration (from TenantDatabaseConfig table) */
163
+ databaseName?: string;
164
+ databaseHost?: string;
165
+ databasePort?: number;
166
+ databaseUsername?: string;
167
+ databasePassword?: string;
168
+ databaseSslMode?: string;
169
+ connectionPoolSize?: number;
170
+ }
171
+
172
+ /**
173
+ * Dynamic module for multi-tenant database management
174
+ *
175
+ * This module provides:
176
+ * - Tenant context management (request-scoped)
177
+ * - Database connection pooling
178
+ * - Dynamic schema/cluster routing
179
+ * - Support for both gateway and microservice modes
180
+ *
181
+ * ## Gateway Mode (API Gateway)
182
+ * - Use DatabaseModule.forServer() method
183
+ * - Automatically extracts tenant from subdomain, falls back to x-tenant-id header
184
+ * - Provide primaryDb configuration and prismaClientConstructor
185
+ * - Automatically queries primary DB for tenant config
186
+ * - Automatically registers TenantContextInterceptor globally
187
+ * - No manual interceptor registration needed
188
+ *
189
+ * ## Microservice Mode (RabbitMQ Workers)
190
+ * - Use DatabaseModule.forMicroservice() method
191
+ * - Only provide prismaClientConstructor
192
+ * - Tenant context comes from RabbitMQ messages
193
+ * - Automatically registers MessageTenantContextInterceptor globally
194
+ * - No manual interceptor registration needed
195
+ *
196
+ * @example
197
+ * // Gateway configuration
198
+ * DatabaseModule.forServer({
199
+ * inject: [ConfigService],
200
+ * useFactory: (config: ConfigService) => ({
201
+ * primaryDb: {
202
+ * host: config.get('PRIMARY_DB_HOST'),
203
+ * port: config.get('PRIMARY_DB_PORT'),
204
+ * username: config.get('PRIMARY_DB_USERNAME'),
205
+ * password: config.get('PRIMARY_DB_PASSWORD'),
206
+ * database: config.get('PRIMARY_DB_DATABASE'),
207
+ * },
208
+ * prismaClientConstructor: PrismaClient,
209
+ * }),
210
+ * })
211
+ *
212
+ * @example
213
+ * // Microservice configuration
214
+ * DatabaseModule.forMicroservice({
215
+ * inject: [ConfigService],
216
+ * useFactory: (config: ConfigService) => ({
217
+ * prismaClientConstructor: PrismaClient,
218
+ * }),
219
+ * })
220
+ */
221
+ declare class DatabaseModule {
222
+ /**
223
+ * Configure DatabaseModule for Gateway/HTTP mode (multi-tenant web servers)
224
+ *
225
+ * This mode is for API Gateways that handle HTTP requests:
226
+ * - Automatically registers TenantContextInterceptor
227
+ * - Extracts tenant from subdomain or x-tenant-id header
228
+ * - Queries primary database for tenant configuration
229
+ * - Provides PrimaryDatabaseService for tenant lookup
230
+ *
231
+ * @param options Async configuration options
232
+ * @returns Dynamic module configuration with HTTP interceptor
233
+ *
234
+ * @example
235
+ * DatabaseModule.forServer({
236
+ * inject: [ConfigService],
237
+ * useFactory: (config: ConfigService) => ({
238
+ * primaryDb: {
239
+ * host: config.get('PRIMARY_DB_HOST'),
240
+ * port: config.get('PRIMARY_DB_PORT'),
241
+ * username: config.get('PRIMARY_DB_USERNAME'),
242
+ * password: config.get('PRIMARY_DB_PASSWORD'),
243
+ * database: config.get('PRIMARY_DB_DATABASE'),
244
+ * },
245
+ * prismaClientConstructor: PrismaClient,
246
+ * }),
247
+ * })
248
+ */
249
+ static forServer(options: {
250
+ useFactory: (...args: any[]) => Promise<DatabaseModuleOptions> | DatabaseModuleOptions;
251
+ inject?: any[];
252
+ }): DynamicModule;
253
+ /**
254
+ * Configure DatabaseModule for Microservice/Messaging mode (RabbitMQ workers)
255
+ *
256
+ * This mode is for microservices that process messages from queues:
257
+ * - Automatically registers MessageTenantContextInterceptor
258
+ * - Extracts tenant from RabbitMQ message patterns
259
+ * - No primary database needed (tenant comes from message context)
260
+ *
261
+ * @param options Async configuration options
262
+ * @returns Dynamic module configuration with message interceptor
263
+ *
264
+ * @example
265
+ * DatabaseModule.forMicroservice({
266
+ * inject: [ConfigService],
267
+ * useFactory: (config: ConfigService) => ({
268
+ * prismaClientConstructor: PrismaClient,
269
+ * }),
270
+ * })
271
+ */
272
+ static forMicroservice(options: {
273
+ useFactory: (...args: any[]) => Promise<DatabaseModuleOptions> | DatabaseModuleOptions;
274
+ inject?: any[];
275
+ }): DynamicModule;
276
+ /**
277
+ * Internal helper to create dynamic module with conditional interceptor registration
278
+ *
279
+ * @param options Configuration options
280
+ * @param mode Mode of operation (gateway or microservice)
281
+ * @returns Dynamic module configuration
282
+ */
283
+ private static createDynamicModule;
284
+ }
285
+
286
+ /**
287
+ * Request-scoped service that holds tenant context for the current request or RabbitMQ message
288
+ *
289
+ * IMPORTANT: This service is REQUEST-SCOPED, meaning NestJS creates a new instance
290
+ * for each HTTP request or RabbitMQ message. This ensures tenant isolation and
291
+ * prevents cross-tenant data leaks in concurrent scenarios.
292
+ *
293
+ * @example
294
+ * // In a controller or service
295
+ * constructor(private readonly tenantContext: TenantContextService) {}
296
+ *
297
+ * async handleRequest() {
298
+ * const tenant = this.tenantContext.getTenant();
299
+ * console.log(`Processing request for tenant: ${tenant.tenantSlug}`);
300
+ * }
301
+ */
302
+ declare class TenantContextService {
303
+ private tenantInfo;
304
+ /**
305
+ * Set tenant information for this request/message
306
+ *
307
+ * This is typically called by:
308
+ * - TenantContextInterceptor (for HTTP requests in gateway)
309
+ * - MessageTenantContextInterceptor (for RabbitMQ messages in microservices)
310
+ * - Manual context setup in message handlers
311
+ *
312
+ * @param tenantInfo Complete tenant information
313
+ * @throws Error if tenant context is already set (prevents accidental overwrites)
314
+ */
315
+ setTenant(tenantInfo: TenantInfo): void;
316
+ /**
317
+ * Get tenant information for this request/message
318
+ *
319
+ * @returns Tenant information
320
+ * @throws UnauthorizedException if tenant context hasn't been set
321
+ */
322
+ getTenant(): TenantInfo;
323
+ /**
324
+ * Check if tenant context has been set
325
+ *
326
+ * @returns true if tenant context is available
327
+ */
328
+ hasTenant(): boolean;
329
+ /**
330
+ * Clear tenant context
331
+ *
332
+ * This is useful for cleanup in RabbitMQ message handlers
333
+ * after the message has been processed.
334
+ *
335
+ * HTTP requests don't need manual cleanup as the service
336
+ * instance is destroyed when the request ends.
337
+ */
338
+ clearTenant(): void;
339
+ /**
340
+ * Get tenant ID safely (returns null if not set)
341
+ *
342
+ * @returns Tenant ID or null
343
+ */
344
+ getTenantIdSafe(): string | null;
345
+ /**
346
+ * Get tenant subdomain safely (returns null if not set)
347
+ *
348
+ * @returns Tenant subdomain or null
349
+ */
350
+ getTenantSubdomainSafe(): string | null;
351
+ }
352
+
353
+ /**
354
+ * Service responsible for managing tenant-scoped database connections
355
+ *
356
+ * This service:
357
+ * - Maintains a connection pool (Map<cacheKey, DbClient>)
358
+ * - Creates new connections dynamically based on tenant context
359
+ * - Reuses existing connections for the same tenant
360
+ * - Supports both cloud schemas and enterprise databases
361
+ * - Automatically cleans up idle connections
362
+ *
363
+ * @example
364
+ * // In a controller or service
365
+ * const dbClient = await this.tenantDatabase.getDbClient<PrismaClient>();
366
+ * const users = await dbClient.user.findMany();
367
+ */
368
+ declare class TenantDatabaseService implements OnModuleDestroy {
369
+ private readonly options;
370
+ private readonly tenantContext;
371
+ private readonly logger;
372
+ /** Connection pool: Map<cacheKey, DbClient> */
373
+ private readonly clients;
374
+ /** Track last usage time for idle connection cleanup */
375
+ private readonly clientLastUsed;
376
+ /** Cleanup interval timer */
377
+ private cleanupInterval?;
378
+ constructor(options: DatabaseModuleOptions, tenantContext: TenantContextService);
379
+ /**
380
+ * Get tenant-scoped database client for the current request/message
381
+ *
382
+ * This method:
383
+ * 1. Gets tenant info from TenantContextService
384
+ * 2. Builds a connection URL based on tenant type
385
+ * 3. Returns cached client if exists, otherwise creates new one
386
+ *
387
+ * @returns Promise<Database client instance>
388
+ * @throws UnauthorizedException if tenant context not set
389
+ * @throws InternalServerErrorException if connection fails
390
+ *
391
+ * @example
392
+ * const dbClient = await tenantDatabase.getDbClient<PrismaClient>();
393
+ * const users = await dbClient.user.findMany();
394
+ */
395
+ getDbClient<T = any>(): Promise<T>;
396
+ /**
397
+ * Create a new database client for the given tenant
398
+ */
399
+ private createDbClient;
400
+ /**
401
+ * Build connection URL for enterprise tenant (dedicated database)
402
+ */
403
+ private buildTenantDbUrl;
404
+ /**
405
+ * Build cache key for connection pooling
406
+ */
407
+ private buildCacheKey;
408
+ /**
409
+ * Start periodic cleanup of idle connections
410
+ */
411
+ private startConnectionCleaner;
412
+ /**
413
+ * Clean up idle connections that haven't been used recently
414
+ */
415
+ private cleanupIdleConnections;
416
+ /**
417
+ * Get current connection pool statistics
418
+ */
419
+ getPoolStats(): {
420
+ activeConnections: number;
421
+ tenants: string[];
422
+ };
423
+ /**
424
+ * Mask password in connection URL for logging
425
+ */
426
+ private maskPassword;
427
+ onModuleDestroy(): Promise<void>;
428
+ }
429
+
430
+ /**
431
+ * Service responsible for querying the primary database to resolve tenant configurations
432
+ *
433
+ * This service:
434
+ * - Connects to the primary database (tenant registry)
435
+ * - Queries tenant metadata (database location, credentials, etc.)
436
+ * - Caches tenant configs in memory to reduce database load
437
+ * - Only used in GATEWAY MODE (microservices receive tenant config from messages)
438
+ *
439
+ * @example
440
+ * // In API Gateway
441
+ * const config = await primaryDatabase.getTenantConfig('acme');
442
+ * // Returns: { id, slug, type, databaseHost, databaseName, ... }
443
+ */
444
+ declare class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {
445
+ private readonly options;
446
+ private readonly logger;
447
+ /** Primary database client for querying tenant registry */
448
+ private primaryDbClient;
449
+ /** In-memory cache: Map<tenantIdentifier, TenantConfig> */
450
+ private readonly tenantConfigCache;
451
+ /** Cache TTL in milliseconds */
452
+ private readonly cacheTTL;
453
+ constructor(options: DatabaseModuleOptions);
454
+ onModuleInit(): Promise<void>;
455
+ /**
456
+ * Initialize connection to primary database
457
+ */
458
+ private initializePrimaryDbClient;
459
+ /**
460
+ * Build connection URL from primary database properties
461
+ */
462
+ private buildPrimaryDbUrl;
463
+ /**
464
+ * Mask password in connection URL for logging
465
+ */
466
+ private maskPassword;
467
+ /**
468
+ * Get tenant configuration by identifier (ID or slug)
469
+ *
470
+ * @param tenantIdentifier Tenant ID or slug
471
+ * @returns Tenant configuration or null if not found
472
+ */
473
+ getTenantInfo(tenantIdentifier: string): Promise<TenantInfo | null>;
474
+ /**
475
+ * Cache tenant information with TTL
476
+ */
477
+ private cacheInfo;
478
+ /**
479
+ * Clear cached tenant information
480
+ *
481
+ * Useful when tenant settings are updated and cache needs to be invalidated
482
+ *
483
+ * @param tenantIdentifier Tenant ID or slug
484
+ */
485
+ clearTenantCache(tenantIdentifier: string): void;
486
+ /**
487
+ * Clear all cached tenant configurations
488
+ */
489
+ clearAllCaches(): void;
490
+ /**
491
+ * Get primary database client for direct database access
492
+ *
493
+ * This is useful for platform admin operations (creating tenants, billing, etc.)
494
+ *
495
+ * @returns Primary database client instance
496
+ * @throws Error if primary database client is not initialized
497
+ */
498
+ getPrimaryDbClient<T = any>(): T;
499
+ /**
500
+ * Decrypt database credentials
501
+ *
502
+ * Override this method to implement your encryption strategy
503
+ *
504
+ * @param encrypted Encrypted value
505
+ * @returns Decrypted value
506
+ */
507
+ private decrypt;
508
+ onModuleDestroy(): Promise<void>;
509
+ }
510
+
511
+ declare class RequestService {
512
+ private readonly request;
513
+ constructor(request: FastifyRequest);
514
+ /**
515
+ * Extract tenant identifier from request headers
516
+ * Priority: x-tenant-id > x-subdomain
517
+ * @returns Tenant identifier or null if not found
518
+ */
519
+ getTenantIdentifier(): string | null;
520
+ /**
521
+ * Extract access token from Authorization header
522
+ * Format: "Bearer <token>"
523
+ * @returns Access token or null if not found
524
+ */
525
+ getAccessToken(): string | null;
526
+ /**
527
+ * Extract refresh token from session-id cookie
528
+ * Cookie name: session-id
529
+ * @returns Refresh token or null if not found
530
+ */
531
+ getRefreshToken(): string | null;
532
+ /**
533
+ * Get a specific header value
534
+ * @param key Header key
535
+ * @returns Header value (string, array, or undefined)
536
+ */
537
+ getHeader(key: string): string | string[] | undefined;
538
+ /**
539
+ * Get all headers
540
+ * @returns Record of all headers
541
+ */
542
+ getAllHeaders(): FastifyRequest['headers'];
543
+ }
544
+
545
+ /**
546
+ * Vritti Authentication Guard - Validates JWT tokens and tenant context
547
+ *
548
+ * This guard performs comprehensive validation and attaches user data to request.
549
+ *
550
+ * Validation Flow:
551
+ * 1. Checks if endpoint is marked with @Public() decorator → skip all validation
552
+ * 2. Checks if endpoint is marked with @Onboarding() decorator:
553
+ * - Requires token type='onboarding'
554
+ * - Validates JWT signature and expiry only
555
+ * - Skips tenant and refresh token validation
556
+ * - Attaches user data to request.user
557
+ * 3. For regular endpoints (no decorator):
558
+ * - Rejects tokens with type='onboarding'
559
+ * - Validates access token (JWT signature, expiry, nbf)
560
+ * - Validates refresh token from session-id cookie
561
+ * - Validates tenant exists and is ACTIVE
562
+ * - Attaches user data to request.user
563
+ *
564
+ * Token Format:
565
+ * - Access Token: "Authorization: Bearer <jwt_token>"
566
+ * - Refresh Token: "session-id" cookie
567
+ *
568
+ * Token Types:
569
+ * - type='onboarding': Limited access during registration flow (@Onboarding endpoints only)
570
+ * - type='access': Full access to authenticated endpoints
571
+ *
572
+ * Environment Variables Required:
573
+ * - JWT_SECRET: Secret key to verify access tokens (required)
574
+ * - JWT_REFRESH_SECRET: Secret key for refresh tokens (optional, falls back to JWT_SECRET)
575
+ *
576
+ * Error Responses:
577
+ * - 401: Invalid/expired access token
578
+ * - 401: Invalid/expired refresh token
579
+ * - 401: Tenant not found or inactive
580
+ * - 401: Tenant identifier not found
581
+ * - 401: Token type mismatch (onboarding token on regular endpoint or vice versa)
582
+ *
583
+ * @example
584
+ * // Automatically registered by AuthConfigModule.forRootAsync()
585
+ * // No manual registration needed
586
+ * //
587
+ * // Internal registration uses useExisting pattern:
588
+ * // providers: [
589
+ * // VrittiAuthGuard,
590
+ * // {
591
+ * // provide: APP_GUARD,
592
+ * // useExisting: VrittiAuthGuard,
593
+ * // },
594
+ * // ]
595
+ *
596
+ * @example
597
+ * // Bypass guard with @Public() decorator
598
+ * @Public()
599
+ * @Post('auth/login')
600
+ * async login(@Body() dto: LoginDto) { ... }
601
+ *
602
+ * @example
603
+ * // Restrict to onboarding tokens with @Onboarding() decorator
604
+ * @Onboarding()
605
+ * @Post('onboarding/verify-email')
606
+ * async verifyEmail(@Request() req) {
607
+ * const userId = req.user.id; // Available from guard
608
+ * ...
609
+ * }
610
+ */
611
+ declare class VrittiAuthGuard implements CanActivate {
612
+ private readonly reflector;
613
+ private readonly configService;
614
+ private readonly jwtService;
615
+ private readonly primaryDatabase;
616
+ private readonly requestService;
617
+ private readonly logger;
618
+ constructor(reflector: Reflector, configService: ConfigService, jwtService: JwtService, primaryDatabase: PrimaryDatabaseService, requestService: RequestService);
619
+ canActivate(context: ExecutionContext): Promise<boolean>;
620
+ /**
621
+ * Validate access token with proper expiry checks
622
+ * Throws UnauthorizedException if token is invalid or expired
623
+ */
624
+ private validateAccessToken;
625
+ /**
626
+ * Validate refresh token with proper expiry checks
627
+ * Throws UnauthorizedException if token is invalid or expired
628
+ */
629
+ private validateRefreshToken;
630
+ /**
631
+ * Helper to validate refresh token with specific secret
632
+ */
633
+ private validateRefreshTokenWithSecret;
634
+ }
635
+
636
+ /**
637
+ * Parameter decorator that injects tenant metadata into controller method
638
+ *
639
+ * This decorator retrieves tenant information (ID, slug, type, etc.)
640
+ * from the REQUEST-SCOPED TenantContextService.
641
+ *
642
+ * Useful for:
643
+ * - Logging tenant-specific information
644
+ * - Implementing tenant-specific business logic
645
+ * - Auditing and tracking
646
+ * - Conditional feature flags
647
+ *
648
+ * @returns TenantInfo object with tenant metadata
649
+ *
650
+ * @example
651
+ * // Access tenant metadata
652
+ * @Get('info')
653
+ * async getTenantInfo(@Tenant() tenant: TenantInfo) {
654
+ * return {
655
+ * id: tenant.id,
656
+ * subdomain: tenant.subdomain,
657
+ * type: tenant.type,
658
+ * };
659
+ * }
660
+ *
661
+ * @example
662
+ * // Use for logging
663
+ * @Post()
664
+ * async createUser(
665
+ * @Body() dto: CreateUserDto,
666
+ * @Tenant() tenant: TenantInfo,
667
+ * ) {
668
+ * this.logger.log(`Creating user for tenant: ${tenant.subdomain}`);
669
+ * // ...
670
+ * }
671
+ *
672
+ * @example
673
+ * // Conditional business logic
674
+ * @Get('features')
675
+ * async getFeatures(@Tenant() tenant: TenantInfo) {
676
+ * if (tenant.type === 'ENTERPRISE') {
677
+ * return ['feature-a', 'feature-b', 'feature-c'];
678
+ * }
679
+ * return ['feature-a'];
680
+ * }
681
+ */
682
+ declare const Tenant: (...dataOrPipes: unknown[]) => ParameterDecorator;
683
+
684
+ /**
685
+ * Onboarding Decorator - Marks endpoints that require onboarding token
686
+ *
687
+ * Use this decorator on controllers or route handlers that should only be
688
+ * accessible during the onboarding flow with JWT tokens containing type='onboarding'.
689
+ *
690
+ * These endpoints:
691
+ * - Accept ONLY tokens with type='onboarding'
692
+ * - Reject regular access tokens (type='access')
693
+ * - Skip tenant validation and refresh token checks
694
+ * - Only validate JWT signature and expiry
695
+ *
696
+ * Useful for:
697
+ * - Email/phone verification during onboarding
698
+ * - Onboarding status checks
699
+ * - Resending OTPs during registration
700
+ *
701
+ * @example
702
+ * // On a controller method
703
+ * @Post('verify-email')
704
+ * @Onboarding()
705
+ * async verifyEmail(@Request() req, @Body() dto: VerifyEmailDto) {
706
+ * const userId = req.user.id; // Available from VrittiAuthGuard
707
+ * return this.service.verifyEmail(userId, dto.otp);
708
+ * }
709
+ *
710
+ * @example
711
+ * // Multiple onboarding endpoints
712
+ * @Controller('onboarding')
713
+ * export class OnboardingController {
714
+ * @Post('verify-email')
715
+ * @Onboarding()
716
+ * async verifyEmail() { ... }
717
+ *
718
+ * @Post('resend-otp')
719
+ * @Onboarding()
720
+ * async resendOtp() { ... }
721
+ * }
722
+ */
723
+ declare const Onboarding: () => _nestjs_common.CustomDecorator<string>;
724
+
725
+ /**
726
+ * Public Decorator - Marks endpoints that don't require authentication
727
+ *
728
+ * Use this decorator on controllers or route handlers to bypass VrittiAuthGuard
729
+ * tenant validation. Useful for:
730
+ * - Login/signup endpoints
731
+ * - Health checks
732
+ * - Public documentation endpoints
733
+ * - Webhook endpoints that don't require tenant context
734
+ *
735
+ * @example
736
+ * // On a controller method
737
+ * @Public()
738
+ * @Post('auth/login')
739
+ * async login(@Body() dto: LoginDto) {
740
+ * return this.authService.login(dto);
741
+ * }
742
+ *
743
+ * @example
744
+ * // On an entire controller
745
+ * @Public()
746
+ * @Controller('health')
747
+ * export class HealthController {
748
+ * @Get()
749
+ * check() {
750
+ * return { status: 'ok' };
751
+ * }
752
+ * }
753
+ */
754
+ declare const Public: () => _nestjs_common.CustomDecorator<string>;
755
+
756
+ export { AuthConfigModule, DatabaseModule, type DatabaseModuleOptions, Onboarding, PrimaryDatabaseService, type PrimaryDbConfig, Public, Tenant, TenantContextService, TenantDatabaseService, type TenantInfo, VrittiAuthGuard };