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