@vritti/api-sdk 0.0.2 → 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.js CHANGED
@@ -1,14 +1,18 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
- // src/database/database.module.ts
5
- import { Global, Module } from "@nestjs/common";
4
+ // src/auth/auth-config.module.ts
5
+ import { Global as Global2, Module as Module2 } from "@nestjs/common";
6
+ import { ConfigModule, ConfigService as ConfigService2 } from "@nestjs/config";
7
+ import { APP_GUARD } from "@nestjs/core";
8
+ import { JwtModule } from "@nestjs/jwt";
6
9
 
7
- // src/database/constants.ts
8
- var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
10
+ // src/request/request.module.ts
11
+ import { Global, Module } from "@nestjs/common";
9
12
 
10
- // src/database/services/primary-database.service.ts
11
- import { Inject, Injectable, InternalServerErrorException, Logger } from "@nestjs/common";
13
+ // src/request/services/request.service.ts
14
+ import { Inject, Injectable, Scope } from "@nestjs/common";
15
+ import { REQUEST } from "@nestjs/core";
12
16
  function _ts_decorate(decorators, target, key, desc) {
13
17
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14
18
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -26,6 +30,141 @@ function _ts_param(paramIndex, decorator) {
26
30
  };
27
31
  }
28
32
  __name(_ts_param, "_ts_param");
33
+ var RequestService = class {
34
+ static {
35
+ __name(this, "RequestService");
36
+ }
37
+ request;
38
+ constructor(request) {
39
+ this.request = request;
40
+ }
41
+ /**
42
+ * Extract tenant identifier from request headers
43
+ * Priority: x-tenant-id > x-subdomain
44
+ * @returns Tenant identifier or null if not found
45
+ */
46
+ getTenantIdentifier() {
47
+ const getHeader = /* @__PURE__ */ __name((key) => {
48
+ const value = this.request.headers?.[key];
49
+ return Array.isArray(value) ? value[0] : value;
50
+ }, "getHeader");
51
+ return getHeader("x-tenant-id") || getHeader("x-subdomain") || null;
52
+ }
53
+ /**
54
+ * Extract access token from Authorization header
55
+ * Format: "Bearer <token>"
56
+ * @returns Access token or null if not found
57
+ */
58
+ getAccessToken() {
59
+ const authHeader = this.request.headers?.authorization;
60
+ if (!authHeader) {
61
+ return null;
62
+ }
63
+ const [type, token] = authHeader.split(" ") ?? [];
64
+ return type === "Bearer" && token ? token : null;
65
+ }
66
+ /**
67
+ * Extract refresh token from session-id cookie
68
+ * Cookie name: session-id
69
+ * @returns Refresh token or null if not found
70
+ */
71
+ getRefreshToken() {
72
+ try {
73
+ const cookies = this.request.cookies;
74
+ if (cookies && typeof cookies === "object") {
75
+ const sessionId = cookies["session-id"];
76
+ if (sessionId) {
77
+ return sessionId;
78
+ }
79
+ }
80
+ return null;
81
+ } catch (error) {
82
+ return null;
83
+ }
84
+ }
85
+ /**
86
+ * Get a specific header value
87
+ * @param key Header key
88
+ * @returns Header value (string, array, or undefined)
89
+ */
90
+ getHeader(key) {
91
+ return this.request.headers?.[key];
92
+ }
93
+ /**
94
+ * Get all headers
95
+ * @returns Record of all headers
96
+ */
97
+ getAllHeaders() {
98
+ return this.request.headers || {};
99
+ }
100
+ };
101
+ RequestService = _ts_decorate([
102
+ Injectable({
103
+ scope: Scope.REQUEST
104
+ }),
105
+ _ts_param(0, Inject(REQUEST)),
106
+ _ts_metadata("design:type", Function),
107
+ _ts_metadata("design:paramtypes", [
108
+ typeof FastifyRequest === "undefined" ? Object : FastifyRequest
109
+ ])
110
+ ], RequestService);
111
+
112
+ // src/request/request.module.ts
113
+ function _ts_decorate2(decorators, target, key, desc) {
114
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
115
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
116
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
117
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
118
+ }
119
+ __name(_ts_decorate2, "_ts_decorate");
120
+ var RequestModule = class {
121
+ static {
122
+ __name(this, "RequestModule");
123
+ }
124
+ };
125
+ RequestModule = _ts_decorate2([
126
+ Global(),
127
+ Module({
128
+ providers: [
129
+ RequestService
130
+ ],
131
+ exports: [
132
+ RequestService
133
+ ]
134
+ })
135
+ ], RequestModule);
136
+
137
+ // src/auth/guards/vritti-auth.guard.ts
138
+ import { Injectable as Injectable3, Logger as Logger2, Scope as Scope2, UnauthorizedException } from "@nestjs/common";
139
+ import { ConfigService } from "@nestjs/config";
140
+ import { Reflector } from "@nestjs/core";
141
+ import { JwtService } from "@nestjs/jwt";
142
+ import * as jwt from "jsonwebtoken";
143
+
144
+ // src/database/services/primary-database.service.ts
145
+ import { Inject as Inject2, Injectable as Injectable2, InternalServerErrorException, Logger } from "@nestjs/common";
146
+
147
+ // src/database/constants.ts
148
+ var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
149
+
150
+ // src/database/services/primary-database.service.ts
151
+ function _ts_decorate3(decorators, target, key, desc) {
152
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
153
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
154
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
155
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
156
+ }
157
+ __name(_ts_decorate3, "_ts_decorate");
158
+ function _ts_metadata2(k, v) {
159
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
160
+ }
161
+ __name(_ts_metadata2, "_ts_metadata");
162
+ function _ts_param2(paramIndex, decorator) {
163
+ return function(target, key) {
164
+ decorator(target, key, paramIndex);
165
+ };
166
+ }
167
+ __name(_ts_param2, "_ts_param");
29
168
  var PrimaryDatabaseService = class _PrimaryDatabaseService {
30
169
  static {
31
170
  __name(this, "PrimaryDatabaseService");
@@ -123,10 +262,13 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
123
262
  id: tenantIdentifier
124
263
  },
125
264
  {
126
- subDomain: tenantIdentifier
265
+ subdomain: tenantIdentifier
127
266
  }
128
267
  ],
129
268
  status: "ACTIVE"
269
+ },
270
+ include: {
271
+ databaseConfig: true
130
272
  }
131
273
  });
132
274
  if (!tenant) {
@@ -136,16 +278,18 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
136
278
  const info = {
137
279
  id: tenant.id,
138
280
  subdomain: tenant.subdomain,
139
- type: tenant.type,
281
+ type: tenant.dbType,
140
282
  status: tenant.status,
141
- schemaName: tenant.schemaName || void 0,
142
- databaseName: tenant.databaseName || void 0,
143
- databaseHost: tenant.databaseHost || void 0,
144
- databasePort: tenant.databasePort || void 0,
145
- databaseUsername: tenant.databaseUsername ? this.decrypt(tenant.databaseUsername) : void 0,
146
- databasePassword: tenant.databasePassword ? this.decrypt(tenant.databasePassword) : void 0,
147
- databaseSslMode: tenant.databaseSslMode || void 0,
148
- connectionPoolSize: tenant.connectionPoolSize || void 0
283
+ // For SHARED tenants: schema name
284
+ schemaName: tenant.databaseConfig?.dbSchema || void 0,
285
+ // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
286
+ databaseName: tenant.databaseConfig?.dbName || void 0,
287
+ databaseHost: tenant.databaseConfig?.dbHost || void 0,
288
+ databasePort: tenant.databaseConfig?.dbPort || void 0,
289
+ databaseUsername: tenant.databaseConfig?.dbUsername ? this.decrypt(tenant.databaseConfig.dbUsername) : void 0,
290
+ databasePassword: tenant.databaseConfig?.dbPassword ? this.decrypt(tenant.databaseConfig.dbPassword) : void 0,
291
+ databaseSslMode: tenant.databaseConfig?.dbSslMode || void 0,
292
+ connectionPoolSize: tenant.databaseConfig?.connectionPoolSize || void 0
149
293
  };
150
294
  this.cacheInfo(info);
151
295
  return info;
@@ -221,24 +365,312 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
221
365
  }
222
366
  }
223
367
  };
224
- PrimaryDatabaseService = _ts_decorate([
225
- Injectable(),
226
- _ts_param(0, Inject(DATABASE_MODULE_OPTIONS)),
227
- _ts_metadata("design:type", Function),
228
- _ts_metadata("design:paramtypes", [
368
+ PrimaryDatabaseService = _ts_decorate3([
369
+ Injectable2(),
370
+ _ts_param2(0, Inject2(DATABASE_MODULE_OPTIONS)),
371
+ _ts_metadata2("design:type", Function),
372
+ _ts_metadata2("design:paramtypes", [
229
373
  typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
230
374
  ])
231
375
  ], PrimaryDatabaseService);
232
376
 
377
+ // src/auth/guards/vritti-auth.guard.ts
378
+ function _ts_decorate4(decorators, target, key, desc) {
379
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
380
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
381
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
382
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
383
+ }
384
+ __name(_ts_decorate4, "_ts_decorate");
385
+ function _ts_metadata3(k, v) {
386
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
387
+ }
388
+ __name(_ts_metadata3, "_ts_metadata");
389
+ var VrittiAuthGuard = class _VrittiAuthGuard {
390
+ static {
391
+ __name(this, "VrittiAuthGuard");
392
+ }
393
+ reflector;
394
+ configService;
395
+ jwtService;
396
+ primaryDatabase;
397
+ requestService;
398
+ logger = new Logger2(_VrittiAuthGuard.name);
399
+ constructor(reflector, configService, jwtService, primaryDatabase, requestService) {
400
+ this.reflector = reflector;
401
+ this.configService = configService;
402
+ this.jwtService = jwtService;
403
+ this.primaryDatabase = primaryDatabase;
404
+ this.requestService = requestService;
405
+ }
406
+ async canActivate(context) {
407
+ const request = context.switchToHttp().getRequest();
408
+ const isPublic = this.reflector.getAllAndOverride("isPublic", [
409
+ context.getHandler(),
410
+ context.getClass()
411
+ ]);
412
+ if (isPublic) {
413
+ this.logger.debug("Public endpoint detected, skipping authentication");
414
+ return true;
415
+ }
416
+ const isOnboarding = this.reflector.getAllAndOverride("isOnboarding", [
417
+ context.getHandler(),
418
+ context.getClass()
419
+ ]);
420
+ try {
421
+ const accessToken = this.requestService.getAccessToken();
422
+ if (!accessToken) {
423
+ this.logger.warn("Access token not found in Authorization header");
424
+ throw new UnauthorizedException("Access token not found");
425
+ }
426
+ const decodedToken = this.jwtService.decode(accessToken);
427
+ if (!decodedToken) {
428
+ this.logger.warn("Failed to decode access token");
429
+ throw new UnauthorizedException("Invalid token format");
430
+ }
431
+ if (isOnboarding) {
432
+ if (decodedToken.type !== "onboarding") {
433
+ this.logger.warn("Onboarding endpoint requires onboarding token");
434
+ throw new UnauthorizedException("This endpoint requires an onboarding token");
435
+ }
436
+ const validatedToken2 = this.validateAccessToken(accessToken);
437
+ this.logger.debug("Onboarding token validated successfully");
438
+ const userId2 = validatedToken2.userId;
439
+ request.user = {
440
+ id: userId2
441
+ };
442
+ return true;
443
+ }
444
+ if (decodedToken.type === "onboarding") {
445
+ this.logger.warn("Regular endpoint accessed with onboarding token");
446
+ throw new UnauthorizedException("Onboarding tokens cannot access this endpoint");
447
+ }
448
+ const validatedToken = this.validateAccessToken(accessToken);
449
+ this.logger.debug("Access token validated successfully");
450
+ const refreshToken = this.requestService.getRefreshToken();
451
+ if (!refreshToken) {
452
+ this.logger.warn("Refresh token (session-id) not found in cookies");
453
+ throw new UnauthorizedException("Refresh token not found");
454
+ }
455
+ this.validateRefreshToken(refreshToken);
456
+ this.logger.debug("Refresh token validated successfully");
457
+ const userId = validatedToken.userId;
458
+ request.user = {
459
+ id: userId
460
+ };
461
+ const tenantIdentifier = this.requestService.getTenantIdentifier();
462
+ if (!tenantIdentifier) {
463
+ this.logger.warn("Tenant identifier not found in request");
464
+ throw new UnauthorizedException("Tenant identifier not found");
465
+ }
466
+ this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
467
+ if (tenantIdentifier === "cloud") {
468
+ this.logger.debug("Platform admin access detected, skipping tenant database validation");
469
+ return true;
470
+ }
471
+ const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
472
+ if (!tenantInfo) {
473
+ this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
474
+ throw new UnauthorizedException("Invalid tenant");
475
+ }
476
+ if (tenantInfo.status !== "ACTIVE") {
477
+ this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
478
+ throw new UnauthorizedException(`Tenant is ${tenantInfo.status}`);
479
+ }
480
+ this.logger.debug(`Tenant validated: ${tenantInfo.subdomain} (${tenantInfo.type})`);
481
+ return true;
482
+ } catch (error) {
483
+ if (error instanceof UnauthorizedException) {
484
+ throw error;
485
+ }
486
+ this.logger.error("Unexpected error in auth guard", error);
487
+ throw new UnauthorizedException("Authentication failed");
488
+ }
489
+ }
490
+ /**
491
+ * Validate access token with proper expiry checks
492
+ * Throws UnauthorizedException if token is invalid or expired
493
+ */
494
+ validateAccessToken(token) {
495
+ try {
496
+ const decoded = this.jwtService.verify(token);
497
+ this.logger.debug(`Access token decoded for user: ${decoded.userId}`);
498
+ if (decoded.exp) {
499
+ const expiryTime = decoded.exp * 1e3;
500
+ const currentTime = Date.now();
501
+ const timeRemaining = expiryTime - currentTime;
502
+ this.logger.debug(`Access token valid for ${Math.floor(timeRemaining / 1e3)} more seconds`);
503
+ }
504
+ return decoded;
505
+ } catch (error) {
506
+ if (error instanceof UnauthorizedException) {
507
+ throw error;
508
+ }
509
+ const jwtError = error;
510
+ if (jwtError?.name === "TokenExpiredError") {
511
+ this.logger.warn(`Access token expired at: ${jwtError?.expiredAt}`);
512
+ throw new UnauthorizedException("Access token has expired");
513
+ }
514
+ if (jwtError?.name === "JsonWebTokenError") {
515
+ this.logger.warn(`Access token verification failed: ${jwtError?.message}`);
516
+ throw new UnauthorizedException("Invalid access token");
517
+ }
518
+ if (jwtError?.name === "NotBeforeError") {
519
+ this.logger.warn("Access token used before valid (nbf claim)");
520
+ throw new UnauthorizedException("Access token not yet valid");
521
+ }
522
+ this.logger.error("Unexpected error validating access token", error);
523
+ throw new UnauthorizedException("Access token validation failed");
524
+ }
525
+ }
526
+ /**
527
+ * Validate refresh token with proper expiry checks
528
+ * Throws UnauthorizedException if token is invalid or expired
529
+ */
530
+ validateRefreshToken(token) {
531
+ const jwtSecret = this.configService.get("JWT_REFRESH_SECRET") || this.configService.get("JWT_SECRET");
532
+ this.validateRefreshTokenWithSecret(token, jwtSecret);
533
+ }
534
+ /**
535
+ * Helper to validate refresh token with specific secret
536
+ */
537
+ validateRefreshTokenWithSecret(token, secret) {
538
+ if (!secret) {
539
+ this.logger.error("JWT secret not configured for refresh token validation");
540
+ throw new UnauthorizedException("Server configuration error");
541
+ }
542
+ try {
543
+ const decoded = jwt.verify(token, secret, {
544
+ algorithms: [
545
+ "HS256",
546
+ "HS512",
547
+ "RS256"
548
+ ]
549
+ });
550
+ this.logger.debug(`Refresh token decoded for user: ${decoded.userId}`);
551
+ if (decoded.exp) {
552
+ const expiryTime = decoded.exp * 1e3;
553
+ const currentTime = Date.now();
554
+ if (currentTime > expiryTime) {
555
+ this.logger.warn("Refresh token has expired");
556
+ throw new UnauthorizedException("Refresh token has expired. Please login again");
557
+ }
558
+ const timeRemaining = expiryTime - currentTime;
559
+ this.logger.debug(`Refresh token valid for ${Math.floor(timeRemaining / 1e3)} more seconds`);
560
+ }
561
+ } catch (error) {
562
+ if (error instanceof UnauthorizedException) {
563
+ throw error;
564
+ }
565
+ const jwtError = error;
566
+ if (jwtError?.name === "TokenExpiredError") {
567
+ this.logger.warn(`Refresh token expired at: ${jwtError?.expiredAt}`);
568
+ throw new UnauthorizedException("Refresh token has expired. Please login again");
569
+ }
570
+ if (jwtError?.name === "JsonWebTokenError") {
571
+ this.logger.warn(`Refresh token verification failed: ${jwtError?.message}`);
572
+ throw new UnauthorizedException("Invalid refresh token");
573
+ }
574
+ if (jwtError?.name === "NotBeforeError") {
575
+ this.logger.warn("Refresh token used before valid (nbf claim)");
576
+ throw new UnauthorizedException("Refresh token not yet valid");
577
+ }
578
+ this.logger.error("Unexpected error validating refresh token", error);
579
+ throw new UnauthorizedException("Refresh token validation failed");
580
+ }
581
+ }
582
+ };
583
+ VrittiAuthGuard = _ts_decorate4([
584
+ Injectable3({
585
+ scope: Scope2.REQUEST
586
+ }),
587
+ _ts_metadata3("design:type", Function),
588
+ _ts_metadata3("design:paramtypes", [
589
+ typeof Reflector === "undefined" ? Object : Reflector,
590
+ typeof ConfigService === "undefined" ? Object : ConfigService,
591
+ typeof JwtService === "undefined" ? Object : JwtService,
592
+ typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
593
+ typeof RequestService === "undefined" ? Object : RequestService
594
+ ])
595
+ ], VrittiAuthGuard);
596
+
597
+ // src/auth/auth-config.module.ts
598
+ function _ts_decorate5(decorators, target, key, desc) {
599
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
600
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
601
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
602
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
603
+ }
604
+ __name(_ts_decorate5, "_ts_decorate");
605
+ var AuthConfigModule = class _AuthConfigModule {
606
+ static {
607
+ __name(this, "AuthConfigModule");
608
+ }
609
+ /**
610
+ * Register the auth module with async configuration
611
+ *
612
+ * This method:
613
+ * 1. Configures JwtModule with JWT_SECRET from ConfigService
614
+ * 2. Provides VrittiAuthGuard globally (applies to all routes)
615
+ * 3. Exports JwtModule for use in other modules (e.g., for signing tokens)
616
+ *
617
+ * @returns Dynamic module configuration
618
+ */
619
+ static forRootAsync() {
620
+ return {
621
+ module: _AuthConfigModule,
622
+ imports: [
623
+ ConfigModule,
624
+ RequestModule,
625
+ JwtModule.registerAsync({
626
+ imports: [
627
+ ConfigModule
628
+ ],
629
+ inject: [
630
+ ConfigService2
631
+ ],
632
+ useFactory: /* @__PURE__ */ __name((config) => ({
633
+ secret: config.get("JWT_SECRET"),
634
+ signOptions: {
635
+ algorithm: "HS256"
636
+ }
637
+ }), "useFactory")
638
+ })
639
+ ],
640
+ providers: [
641
+ {
642
+ provide: APP_GUARD,
643
+ useClass: VrittiAuthGuard
644
+ }
645
+ ],
646
+ exports: [
647
+ JwtModule
648
+ ]
649
+ };
650
+ }
651
+ };
652
+ AuthConfigModule = _ts_decorate5([
653
+ Global2(),
654
+ Module2({})
655
+ ], AuthConfigModule);
656
+
657
+ // src/database/database.module.ts
658
+ import { Global as Global3, Module as Module3 } from "@nestjs/common";
659
+ import { APP_INTERCEPTOR } from "@nestjs/core";
660
+
661
+ // src/database/interceptors/message-tenant-context.interceptor.ts
662
+ import { Injectable as Injectable5, Logger as Logger3, Scope as Scope4 } from "@nestjs/common";
663
+ import { tap } from "rxjs/operators";
664
+
233
665
  // src/database/services/tenant-context.service.ts
234
- import { Injectable as Injectable2, Scope, UnauthorizedException } from "@nestjs/common";
235
- function _ts_decorate2(decorators, target, key, desc) {
666
+ import { Injectable as Injectable4, Scope as Scope3, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
667
+ function _ts_decorate6(decorators, target, key, desc) {
236
668
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
237
669
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
238
670
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
239
671
  return c > 3 && r && Object.defineProperty(target, key, r), r;
240
672
  }
241
- __name(_ts_decorate2, "_ts_decorate");
673
+ __name(_ts_decorate6, "_ts_decorate");
242
674
  var TenantContextService = class {
243
675
  static {
244
676
  __name(this, "TenantContextService");
@@ -269,7 +701,7 @@ var TenantContextService = class {
269
701
  */
270
702
  getTenant() {
271
703
  if (!this.tenantInfo) {
272
- throw new UnauthorizedException("Tenant context not set");
704
+ throw new UnauthorizedException2("Tenant context not set");
273
705
  }
274
706
  return this.tenantInfo;
275
707
  }
@@ -310,71 +742,214 @@ var TenantContextService = class {
310
742
  return this.tenantInfo?.subdomain ?? null;
311
743
  }
312
744
  };
313
- TenantContextService = _ts_decorate2([
314
- Injectable2({
315
- scope: Scope.REQUEST
745
+ TenantContextService = _ts_decorate6([
746
+ Injectable4({
747
+ scope: Scope3.REQUEST
316
748
  })
317
749
  ], TenantContextService);
318
750
 
319
- // src/database/services/tenant-database.service.ts
320
- import { Inject as Inject2, Injectable as Injectable3, InternalServerErrorException as InternalServerErrorException2, Logger as Logger2 } from "@nestjs/common";
321
- function _ts_decorate3(decorators, target, key, desc) {
751
+ // src/database/interceptors/message-tenant-context.interceptor.ts
752
+ function _ts_decorate7(decorators, target, key, desc) {
322
753
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
323
754
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
324
755
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
325
756
  return c > 3 && r && Object.defineProperty(target, key, r), r;
326
757
  }
327
- __name(_ts_decorate3, "_ts_decorate");
328
- function _ts_metadata2(k, v) {
758
+ __name(_ts_decorate7, "_ts_decorate");
759
+ function _ts_metadata4(k, v) {
329
760
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
330
761
  }
331
- __name(_ts_metadata2, "_ts_metadata");
332
- function _ts_param2(paramIndex, decorator) {
333
- return function(target, key) {
334
- decorator(target, key, paramIndex);
335
- };
336
- }
337
- __name(_ts_param2, "_ts_param");
338
- var TenantDatabaseService = class _TenantDatabaseService {
762
+ __name(_ts_metadata4, "_ts_metadata");
763
+ var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
339
764
  static {
340
- __name(this, "TenantDatabaseService");
765
+ __name(this, "MessageTenantContextInterceptor");
341
766
  }
342
- options;
343
767
  tenantContext;
344
- logger = new Logger2(_TenantDatabaseService.name);
345
- /** Connection pool: Map<cacheKey, DbClient> */
346
- clients = /* @__PURE__ */ new Map();
347
- /** Track last usage time for idle connection cleanup */
348
- clientLastUsed = /* @__PURE__ */ new Map();
349
- /** Cleanup interval timer */
350
- cleanupInterval;
351
- constructor(options, tenantContext) {
352
- this.options = options;
768
+ logger = new Logger3(_MessageTenantContextInterceptor.name);
769
+ constructor(tenantContext) {
353
770
  this.tenantContext = tenantContext;
354
- this.startConnectionCleaner();
355
771
  }
356
- /**
357
- * Get tenant-scoped database client for the current request/message
358
- *
359
- * This method:
360
- * 1. Gets tenant info from TenantContextService
361
- * 2. Builds a connection URL based on tenant type
362
- * 3. Returns cached client if exists, otherwise creates new one
363
- *
364
- * @returns Promise<Database client instance>
365
- * @throws UnauthorizedException if tenant context not set
366
- * @throws InternalServerErrorException if connection fails
367
- *
368
- * @example
369
- * const dbClient = await tenantDatabase.getDbClient<PrismaClient>();
370
- * const users = await dbClient.user.findMany();
371
- */
372
- async getDbClient() {
373
- const tenant = this.tenantContext.getTenant();
374
- const cacheKey = this.buildCacheKey(tenant);
375
- if (this.clients.has(cacheKey)) {
376
- this.clientLastUsed.set(cacheKey, Date.now());
377
- this.logger.debug(`Reusing cached connection: ${cacheKey}`);
772
+ intercept(context, next) {
773
+ const contextType = context.getType();
774
+ if (contextType === "rpc") {
775
+ const rpcContext = context.switchToRpc();
776
+ const payload = rpcContext.getData();
777
+ if (payload && payload.tenant) {
778
+ const tenant = payload.tenant;
779
+ this.logger.debug(`Setting tenant context from message: ${tenant.subdomain}`);
780
+ try {
781
+ this.tenantContext.setTenant(tenant);
782
+ this.logger.log(`Tenant context set: ${tenant.subdomain} (${tenant.type})`);
783
+ } catch (error) {
784
+ this.logger.error("Failed to set tenant context from message", error);
785
+ }
786
+ } else {
787
+ this.logger.warn("Message payload missing tenant information");
788
+ }
789
+ }
790
+ return next.handle().pipe(tap({
791
+ next: /* @__PURE__ */ __name(() => {
792
+ this.cleanupContext();
793
+ }, "next"),
794
+ error: /* @__PURE__ */ __name(() => {
795
+ this.cleanupContext();
796
+ }, "error"),
797
+ complete: /* @__PURE__ */ __name(() => {
798
+ this.cleanupContext();
799
+ }, "complete")
800
+ }));
801
+ }
802
+ /**
803
+ * Clean up tenant context after message is processed
804
+ */
805
+ cleanupContext() {
806
+ if (this.tenantContext.hasTenant()) {
807
+ const tenant = this.tenantContext.getTenantIdSafe();
808
+ this.tenantContext.clearTenant();
809
+ this.logger.debug(`Cleaned up tenant context: ${tenant}`);
810
+ }
811
+ }
812
+ };
813
+ MessageTenantContextInterceptor = _ts_decorate7([
814
+ Injectable5({
815
+ scope: Scope4.REQUEST
816
+ }),
817
+ _ts_metadata4("design:type", Function),
818
+ _ts_metadata4("design:paramtypes", [
819
+ typeof TenantContextService === "undefined" ? Object : TenantContextService
820
+ ])
821
+ ], MessageTenantContextInterceptor);
822
+
823
+ // src/database/interceptors/tenant-context.interceptor.ts
824
+ import { Injectable as Injectable6, Logger as Logger4, Scope as Scope5, UnauthorizedException as UnauthorizedException3 } from "@nestjs/common";
825
+ function _ts_decorate8(decorators, target, key, desc) {
826
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
827
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
828
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
829
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
830
+ }
831
+ __name(_ts_decorate8, "_ts_decorate");
832
+ function _ts_metadata5(k, v) {
833
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
834
+ }
835
+ __name(_ts_metadata5, "_ts_metadata");
836
+ var TenantContextInterceptor = class _TenantContextInterceptor {
837
+ static {
838
+ __name(this, "TenantContextInterceptor");
839
+ }
840
+ tenantContext;
841
+ primaryDatabase;
842
+ requestService;
843
+ logger = new Logger4(_TenantContextInterceptor.name);
844
+ constructor(tenantContext, primaryDatabase, requestService) {
845
+ this.tenantContext = tenantContext;
846
+ this.primaryDatabase = primaryDatabase;
847
+ this.requestService = requestService;
848
+ }
849
+ async intercept(context, next) {
850
+ const request = context.switchToHttp().getRequest();
851
+ this.logger.debug(`Processing request: ${request.method} ${request.url}`);
852
+ try {
853
+ const tenantIdentifier = this.requestService.getTenantIdentifier();
854
+ if (!tenantIdentifier) {
855
+ throw new UnauthorizedException3("Tenant identifier not found in request");
856
+ }
857
+ this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
858
+ if (tenantIdentifier === "cloud") {
859
+ this.logger.log("Cloud platform access detected, skipping tenant context setup");
860
+ return next.handle();
861
+ }
862
+ const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
863
+ if (!tenantInfo) {
864
+ this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
865
+ throw new UnauthorizedException3("Invalid tenant");
866
+ }
867
+ if (tenantInfo.status !== "ACTIVE") {
868
+ this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
869
+ throw new UnauthorizedException3(`Tenant is ${tenantInfo.status}`);
870
+ }
871
+ this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
872
+ this.tenantContext.setTenant(tenantInfo);
873
+ request.tenant = tenantInfo;
874
+ this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
875
+ } catch (error) {
876
+ this.logger.error("Failed to set tenant context", error);
877
+ throw error;
878
+ }
879
+ return next.handle();
880
+ }
881
+ };
882
+ TenantContextInterceptor = _ts_decorate8([
883
+ Injectable6({
884
+ scope: Scope5.REQUEST
885
+ }),
886
+ _ts_metadata5("design:type", Function),
887
+ _ts_metadata5("design:paramtypes", [
888
+ typeof TenantContextService === "undefined" ? Object : TenantContextService,
889
+ typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
890
+ typeof RequestService === "undefined" ? Object : RequestService
891
+ ])
892
+ ], TenantContextInterceptor);
893
+
894
+ // src/database/services/tenant-database.service.ts
895
+ import { Inject as Inject3, Injectable as Injectable7, InternalServerErrorException as InternalServerErrorException2, Logger as Logger5 } from "@nestjs/common";
896
+ function _ts_decorate9(decorators, target, key, desc) {
897
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
898
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
899
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
900
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
901
+ }
902
+ __name(_ts_decorate9, "_ts_decorate");
903
+ function _ts_metadata6(k, v) {
904
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
905
+ }
906
+ __name(_ts_metadata6, "_ts_metadata");
907
+ function _ts_param3(paramIndex, decorator) {
908
+ return function(target, key) {
909
+ decorator(target, key, paramIndex);
910
+ };
911
+ }
912
+ __name(_ts_param3, "_ts_param");
913
+ var TenantDatabaseService = class _TenantDatabaseService {
914
+ static {
915
+ __name(this, "TenantDatabaseService");
916
+ }
917
+ options;
918
+ tenantContext;
919
+ logger = new Logger5(_TenantDatabaseService.name);
920
+ /** Connection pool: Map<cacheKey, DbClient> */
921
+ clients = /* @__PURE__ */ new Map();
922
+ /** Track last usage time for idle connection cleanup */
923
+ clientLastUsed = /* @__PURE__ */ new Map();
924
+ /** Cleanup interval timer */
925
+ cleanupInterval;
926
+ constructor(options, tenantContext) {
927
+ this.options = options;
928
+ this.tenantContext = tenantContext;
929
+ this.startConnectionCleaner();
930
+ }
931
+ /**
932
+ * Get tenant-scoped database client for the current request/message
933
+ *
934
+ * This method:
935
+ * 1. Gets tenant info from TenantContextService
936
+ * 2. Builds a connection URL based on tenant type
937
+ * 3. Returns cached client if exists, otherwise creates new one
938
+ *
939
+ * @returns Promise<Database client instance>
940
+ * @throws UnauthorizedException if tenant context not set
941
+ * @throws InternalServerErrorException if connection fails
942
+ *
943
+ * @example
944
+ * const dbClient = await tenantDatabase.getDbClient<PrismaClient>();
945
+ * const users = await dbClient.user.findMany();
946
+ */
947
+ async getDbClient() {
948
+ const tenant = this.tenantContext.getTenant();
949
+ const cacheKey = this.buildCacheKey(tenant);
950
+ if (this.clients.has(cacheKey)) {
951
+ this.clientLastUsed.set(cacheKey, Date.now());
952
+ this.logger.debug(`Reusing cached connection: ${cacheKey}`);
378
953
  return this.clients.get(cacheKey);
379
954
  }
380
955
  this.logger.log(`Creating new database connection: ${cacheKey}`);
@@ -497,87 +1072,116 @@ var TenantDatabaseService = class _TenantDatabaseService {
497
1072
  this.logger.log("All database connections closed");
498
1073
  }
499
1074
  };
500
- TenantDatabaseService = _ts_decorate3([
501
- Injectable3(),
502
- _ts_param2(0, Inject2(DATABASE_MODULE_OPTIONS)),
503
- _ts_metadata2("design:type", Function),
504
- _ts_metadata2("design:paramtypes", [
1075
+ TenantDatabaseService = _ts_decorate9([
1076
+ Injectable7(),
1077
+ _ts_param3(0, Inject3(DATABASE_MODULE_OPTIONS)),
1078
+ _ts_metadata6("design:type", Function),
1079
+ _ts_metadata6("design:paramtypes", [
505
1080
  typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions,
506
1081
  typeof TenantContextService === "undefined" ? Object : TenantContextService
507
1082
  ])
508
1083
  ], TenantDatabaseService);
509
1084
 
510
1085
  // src/database/database.module.ts
511
- function _ts_decorate4(decorators, target, key, desc) {
1086
+ function _ts_decorate10(decorators, target, key, desc) {
512
1087
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
513
1088
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
514
1089
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
515
1090
  return c > 3 && r && Object.defineProperty(target, key, r), r;
516
1091
  }
517
- __name(_ts_decorate4, "_ts_decorate");
1092
+ __name(_ts_decorate10, "_ts_decorate");
518
1093
  var DatabaseModule = class _DatabaseModule {
519
1094
  static {
520
1095
  __name(this, "DatabaseModule");
521
1096
  }
522
1097
  /**
523
- * Synchronous configuration
1098
+ * Configure DatabaseModule for Gateway/HTTP mode (multi-tenant web servers)
524
1099
  *
525
- * @param options Module configuration options
526
- * @returns Dynamic module configuration
1100
+ * This mode is for API Gateways that handle HTTP requests:
1101
+ * - Automatically registers TenantContextInterceptor
1102
+ * - Extracts tenant from subdomain or x-tenant-id header
1103
+ * - Queries primary database for tenant configuration
1104
+ * - Provides PrimaryDatabaseService for tenant lookup
1105
+ *
1106
+ * @param options Async configuration options
1107
+ * @returns Dynamic module configuration with HTTP interceptor
1108
+ *
1109
+ * @example
1110
+ * DatabaseModule.forServer({
1111
+ * inject: [ConfigService],
1112
+ * useFactory: (config: ConfigService) => ({
1113
+ * primaryDb: {
1114
+ * host: config.get('PRIMARY_DB_HOST'),
1115
+ * port: config.get('PRIMARY_DB_PORT'),
1116
+ * username: config.get('PRIMARY_DB_USERNAME'),
1117
+ * password: config.get('PRIMARY_DB_PASSWORD'),
1118
+ * database: config.get('PRIMARY_DB_DATABASE'),
1119
+ * },
1120
+ * prismaClientConstructor: PrismaClient,
1121
+ * }),
1122
+ * })
527
1123
  */
528
- static forRoot(options) {
529
- const providers = [
530
- {
531
- provide: DATABASE_MODULE_OPTIONS,
532
- useValue: options
533
- },
534
- TenantDatabaseService,
535
- TenantContextService,
536
- PrimaryDatabaseService
537
- ];
538
- return {
539
- module: _DatabaseModule,
540
- providers,
541
- exports: [
542
- TenantDatabaseService,
543
- TenantContextService,
544
- PrimaryDatabaseService
545
- ]
546
- };
1124
+ static forServer(options) {
1125
+ return this.createDynamicModule(options, "gateway");
547
1126
  }
548
1127
  /**
549
- * Asynchronous configuration (recommended)
1128
+ * Configure DatabaseModule for Microservice/Messaging mode (RabbitMQ workers)
550
1129
  *
551
- * Allows injecting ConfigService or other dependencies
1130
+ * This mode is for microservices that process messages from queues:
1131
+ * - Automatically registers MessageTenantContextInterceptor
1132
+ * - Extracts tenant from RabbitMQ message patterns
1133
+ * - No primary database needed (tenant comes from message context)
552
1134
  *
553
1135
  * @param options Async configuration options
554
- * @returns Dynamic module configuration
1136
+ * @returns Dynamic module configuration with message interceptor
555
1137
  *
556
1138
  * @example
557
- * DatabaseModule.forRootAsync({
558
- * imports: [ConfigModule],
559
- * useFactory: async (config: ConfigService) => ({
560
- * cloudDatabaseUrl: config.get('CLOUD_DATABASE_URL'),
1139
+ * DatabaseModule.forMicroservice({
1140
+ * inject: [ConfigService],
1141
+ * useFactory: (config: ConfigService) => ({
561
1142
  * prismaClientConstructor: PrismaClient,
562
- * tenantResolver: 'subdomain',
563
1143
  * }),
564
- * inject: [ConfigService],
565
1144
  * })
566
1145
  */
567
- static forRootAsync(options) {
1146
+ static forMicroservice(options) {
1147
+ return this.createDynamicModule(options, "microservice");
1148
+ }
1149
+ /**
1150
+ * Internal helper to create dynamic module with conditional interceptor registration
1151
+ *
1152
+ * @param options Configuration options
1153
+ * @param mode Mode of operation (gateway or microservice)
1154
+ * @returns Dynamic module configuration
1155
+ */
1156
+ static createDynamicModule(options, mode) {
568
1157
  const asyncProvider = {
569
1158
  provide: DATABASE_MODULE_OPTIONS,
570
1159
  useFactory: options.useFactory,
571
1160
  inject: options.inject || []
572
1161
  };
1162
+ const providers = [
1163
+ asyncProvider,
1164
+ TenantContextService,
1165
+ PrimaryDatabaseService,
1166
+ TenantDatabaseService
1167
+ ];
1168
+ if (mode === "gateway") {
1169
+ providers.push({
1170
+ provide: APP_INTERCEPTOR,
1171
+ useClass: TenantContextInterceptor
1172
+ });
1173
+ } else {
1174
+ providers.push({
1175
+ provide: APP_INTERCEPTOR,
1176
+ useClass: MessageTenantContextInterceptor
1177
+ });
1178
+ }
573
1179
  return {
574
1180
  module: _DatabaseModule,
575
- providers: [
576
- asyncProvider,
577
- TenantContextService,
578
- PrimaryDatabaseService,
579
- TenantDatabaseService
1181
+ imports: [
1182
+ RequestModule
580
1183
  ],
1184
+ providers,
581
1185
  exports: [
582
1186
  TenantDatabaseService,
583
1187
  TenantContextService,
@@ -587,217 +1191,11 @@ var DatabaseModule = class _DatabaseModule {
587
1191
  };
588
1192
  }
589
1193
  };
590
- DatabaseModule = _ts_decorate4([
591
- Global(),
592
- Module({})
1194
+ DatabaseModule = _ts_decorate10([
1195
+ Global3(),
1196
+ Module3({})
593
1197
  ], DatabaseModule);
594
1198
 
595
- // src/database/interceptors/message-tenant-context.interceptor.ts
596
- import { Injectable as Injectable4, Logger as Logger3, Scope as Scope2 } from "@nestjs/common";
597
- import { tap } from "rxjs/operators";
598
- function _ts_decorate5(decorators, target, key, desc) {
599
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
600
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
601
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
602
- return c > 3 && r && Object.defineProperty(target, key, r), r;
603
- }
604
- __name(_ts_decorate5, "_ts_decorate");
605
- function _ts_metadata3(k, v) {
606
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
607
- }
608
- __name(_ts_metadata3, "_ts_metadata");
609
- var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
610
- static {
611
- __name(this, "MessageTenantContextInterceptor");
612
- }
613
- tenantContext;
614
- logger = new Logger3(_MessageTenantContextInterceptor.name);
615
- constructor(tenantContext) {
616
- this.tenantContext = tenantContext;
617
- }
618
- intercept(context, next) {
619
- const contextType = context.getType();
620
- if (contextType === "rpc") {
621
- const rpcContext = context.switchToRpc();
622
- const payload = rpcContext.getData();
623
- if (payload && payload.tenant) {
624
- const tenant = payload.tenant;
625
- this.logger.debug(`Setting tenant context from message: ${tenant.subdomain}`);
626
- try {
627
- this.tenantContext.setTenant(tenant);
628
- this.logger.log(`Tenant context set: ${tenant.subdomain} (${tenant.type})`);
629
- } catch (error) {
630
- this.logger.error("Failed to set tenant context from message", error);
631
- }
632
- } else {
633
- this.logger.warn("Message payload missing tenant information");
634
- }
635
- }
636
- return next.handle().pipe(tap({
637
- next: /* @__PURE__ */ __name(() => {
638
- this.cleanupContext();
639
- }, "next"),
640
- error: /* @__PURE__ */ __name(() => {
641
- this.cleanupContext();
642
- }, "error"),
643
- complete: /* @__PURE__ */ __name(() => {
644
- this.cleanupContext();
645
- }, "complete")
646
- }));
647
- }
648
- /**
649
- * Clean up tenant context after message is processed
650
- */
651
- cleanupContext() {
652
- if (this.tenantContext.hasTenant()) {
653
- const tenant = this.tenantContext.getTenantIdSafe();
654
- this.tenantContext.clearTenant();
655
- this.logger.debug(`Cleaned up tenant context: ${tenant}`);
656
- }
657
- }
658
- };
659
- MessageTenantContextInterceptor = _ts_decorate5([
660
- Injectable4({
661
- scope: Scope2.REQUEST
662
- }),
663
- _ts_metadata3("design:type", Function),
664
- _ts_metadata3("design:paramtypes", [
665
- typeof TenantContextService === "undefined" ? Object : TenantContextService
666
- ])
667
- ], MessageTenantContextInterceptor);
668
-
669
- // src/database/interceptors/tenant-context.interceptor.ts
670
- import { Inject as Inject3, Injectable as Injectable5, Logger as Logger4, Scope as Scope3, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
671
-
672
- // src/database/utils/subdomain-parser.util.ts
673
- function extractSubdomain(host) {
674
- if (!host) {
675
- return null;
676
- }
677
- const hostname = host.split(":")[0];
678
- if (!hostname) {
679
- return null;
680
- }
681
- const parts = hostname.split(".");
682
- if (parts.length < 3) {
683
- return null;
684
- }
685
- return parts[0] ?? null;
686
- }
687
- __name(extractSubdomain, "extractSubdomain");
688
-
689
- // src/database/interceptors/tenant-context.interceptor.ts
690
- function _ts_decorate6(decorators, target, key, desc) {
691
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
692
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
693
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
694
- return c > 3 && r && Object.defineProperty(target, key, r), r;
695
- }
696
- __name(_ts_decorate6, "_ts_decorate");
697
- function _ts_metadata4(k, v) {
698
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
699
- }
700
- __name(_ts_metadata4, "_ts_metadata");
701
- function _ts_param3(paramIndex, decorator) {
702
- return function(target, key) {
703
- decorator(target, key, paramIndex);
704
- };
705
- }
706
- __name(_ts_param3, "_ts_param");
707
- var TenantContextInterceptor = class _TenantContextInterceptor {
708
- static {
709
- __name(this, "TenantContextInterceptor");
710
- }
711
- tenantContext;
712
- primaryDatabase;
713
- options;
714
- logger = new Logger4(_TenantContextInterceptor.name);
715
- constructor(tenantContext, primaryDatabase, options) {
716
- this.tenantContext = tenantContext;
717
- this.primaryDatabase = primaryDatabase;
718
- this.options = options;
719
- }
720
- async intercept(context, next) {
721
- const request = context.switchToHttp().getRequest();
722
- this.logger.debug(`Processing request: ${request.method} ${request.url}`);
723
- try {
724
- const tenantIdentifier = this.extractTenantIdentifier(request);
725
- if (!tenantIdentifier) {
726
- throw new UnauthorizedException2("Tenant identifier not found in request");
727
- }
728
- this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
729
- if (tenantIdentifier === "cloud") {
730
- this.logger.log("Cloud platform access detected, skipping tenant context setup");
731
- return next.handle();
732
- }
733
- const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
734
- if (!tenantInfo) {
735
- this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
736
- throw new UnauthorizedException2("Invalid tenant");
737
- }
738
- if (tenantInfo.status !== "ACTIVE") {
739
- this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
740
- throw new UnauthorizedException2(`Tenant is ${tenantInfo.status}`);
741
- }
742
- this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
743
- this.tenantContext.setTenant(tenantInfo);
744
- request.tenant = tenantInfo;
745
- this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
746
- } catch (error) {
747
- this.logger.error("Failed to set tenant context", error);
748
- throw error;
749
- }
750
- return next.handle();
751
- }
752
- /**
753
- * Extract tenant identifier: tries subdomain first, then falls back to header
754
- */
755
- extractTenantIdentifier(request) {
756
- let tenantIdentifier = this.extractFromSubdomain(request);
757
- if (!tenantIdentifier) {
758
- tenantIdentifier = this.extractFromHeader(request);
759
- if (tenantIdentifier) {
760
- this.logger.debug("Using tenant from header (subdomain not found)");
761
- }
762
- }
763
- return tenantIdentifier;
764
- }
765
- /**
766
- * Extract tenant from subdomain
767
- * @example acme.vritti.com → 'acme'
768
- */
769
- extractFromSubdomain(request) {
770
- if (request.subdomain) {
771
- return request.subdomain;
772
- }
773
- const host = request.headers?.host || request.hostname;
774
- return extractSubdomain(host);
775
- }
776
- /**
777
- * Extract tenant from HTTP headers
778
- * Checks x-tenant-id and x-subdomain headers
779
- */
780
- extractFromHeader(request) {
781
- const getHeader = /* @__PURE__ */ __name((key) => {
782
- const value = request.headers?.[key];
783
- return Array.isArray(value) ? value[0] : value;
784
- }, "getHeader");
785
- return getHeader("x-tenant-id") || getHeader("x-subdomain") || null;
786
- }
787
- };
788
- TenantContextInterceptor = _ts_decorate6([
789
- Injectable5({
790
- scope: Scope3.REQUEST
791
- }),
792
- _ts_param3(2, Inject3(DATABASE_MODULE_OPTIONS)),
793
- _ts_metadata4("design:type", Function),
794
- _ts_metadata4("design:paramtypes", [
795
- typeof TenantContextService === "undefined" ? Object : TenantContextService,
796
- typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
797
- typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
798
- ])
799
- ], TenantContextInterceptor);
800
-
801
1199
  // src/database/decorators/tenant.decorator.ts
802
1200
  import { createParamDecorator } from "@nestjs/common";
803
1201
  var Tenant = createParamDecorator((data, ctx) => {
@@ -808,14 +1206,23 @@ var Tenant = createParamDecorator((data, ctx) => {
808
1206
  }
809
1207
  return tenantContext.getTenant();
810
1208
  });
1209
+
1210
+ // src/auth/decorators/onboarding.decorator.ts
1211
+ import { SetMetadata } from "@nestjs/common";
1212
+ var Onboarding = /* @__PURE__ */ __name(() => SetMetadata("isOnboarding", true), "Onboarding");
1213
+
1214
+ // src/auth/decorators/public.decorator.ts
1215
+ import { SetMetadata as SetMetadata2 } from "@nestjs/common";
1216
+ var Public = /* @__PURE__ */ __name(() => SetMetadata2("isPublic", true), "Public");
811
1217
  export {
1218
+ AuthConfigModule,
812
1219
  DatabaseModule,
813
- MessageTenantContextInterceptor,
1220
+ Onboarding,
814
1221
  PrimaryDatabaseService,
1222
+ Public,
815
1223
  Tenant,
816
- TenantContextInterceptor,
817
1224
  TenantContextService,
818
1225
  TenantDatabaseService,
819
- extractSubdomain
1226
+ VrittiAuthGuard
820
1227
  };
821
1228
  //# sourceMappingURL=index.js.map