@vritti/api-sdk 0.1.2 → 0.1.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
@@ -40,7 +40,7 @@ __export(index_exports, {
40
40
  CsrfGuard: () => CsrfGuard,
41
41
  DEFAULT_CORRELATION_HEADER: () => DEFAULT_CORRELATION_HEADER,
42
42
  DatabaseModule: () => DatabaseModule,
43
- ForbiddenException: () => ForbiddenException2,
43
+ ForbiddenException: () => ForbiddenException,
44
44
  GoneException: () => GoneException,
45
45
  HttpExceptionFilter: () => HttpExceptionFilter,
46
46
  HttpLoggerInterceptor: () => HttpLoggerInterceptor,
@@ -56,13 +56,13 @@ __export(index_exports, {
56
56
  Onboarding: () => Onboarding,
57
57
  PayloadTooLargeException: () => PayloadTooLargeException,
58
58
  PrimaryBaseRepository: () => PrimaryBaseRepository,
59
- PrimaryDatabaseService: () => PrimaryDatabaseService,
59
+ PrimaryDatabaseService: () => PrimaryDatabaseService2,
60
60
  Public: () => Public,
61
61
  RequestTimeoutException: () => RequestTimeoutException,
62
62
  ServiceUnavailableException: () => ServiceUnavailableException,
63
63
  Tenant: () => Tenant,
64
64
  TenantBaseRepository: () => TenantBaseRepository,
65
- TenantContextService: () => TenantContextService,
65
+ TenantContextService: () => TenantContextService2,
66
66
  TenantDatabaseService: () => TenantDatabaseService,
67
67
  TooManyRequestsException: () => TooManyRequestsException,
68
68
  UnauthorizedException: () => UnauthorizedException4,
@@ -88,6 +88,19 @@ __export(index_exports, {
88
88
  });
89
89
  module.exports = __toCommonJS(index_exports);
90
90
 
91
+ // src/auth/auth-config.module.ts
92
+ var import_common4 = require("@nestjs/common");
93
+ var import_config3 = require("@nestjs/config");
94
+ var import_core2 = require("@nestjs/core");
95
+ var import_jwt = require("@nestjs/jwt");
96
+
97
+ // src/request/request.module.ts
98
+ var import_common2 = require("@nestjs/common");
99
+
100
+ // src/request/services/request.service.ts
101
+ var import_common = require("@nestjs/common");
102
+ var import_core = require("@nestjs/core");
103
+
91
104
  // src/config/index.ts
92
105
  var defaultConfig = {
93
106
  cookie: {
@@ -162,31 +175,7 @@ function getJwtExpiry() {
162
175
  }
163
176
  __name(getJwtExpiry, "getJwtExpiry");
164
177
 
165
- // src/auth/utils/token-hash.util.ts
166
- var crypto = __toESM(require("crypto"), 1);
167
- function hashToken(token) {
168
- return crypto.createHash("sha256").update(token).digest("hex");
169
- }
170
- __name(hashToken, "hashToken");
171
- function verifyTokenHash(token, expectedHash) {
172
- const computedHash = hashToken(token);
173
- if (computedHash.length !== expectedHash.length) return false;
174
- return crypto.timingSafeEqual(Buffer.from(computedHash, "hex"), Buffer.from(expectedHash, "hex"));
175
- }
176
- __name(verifyTokenHash, "verifyTokenHash");
177
-
178
- // src/auth/auth-config.module.ts
179
- var import_common5 = require("@nestjs/common");
180
- var import_config4 = require("@nestjs/config");
181
- var import_core3 = require("@nestjs/core");
182
- var import_jwt2 = require("@nestjs/jwt");
183
-
184
- // src/request/request.module.ts
185
- var import_common2 = require("@nestjs/common");
186
-
187
178
  // src/request/services/request.service.ts
188
- var import_common = require("@nestjs/common");
189
- var import_core = require("@nestjs/core");
190
179
  function _ts_decorate(decorators, target, key, desc) {
191
180
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
192
181
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -204,7 +193,7 @@ function _ts_param(paramIndex, decorator) {
204
193
  };
205
194
  }
206
195
  __name(_ts_param, "_ts_param");
207
- var RequestService = class {
196
+ var RequestService2 = class {
208
197
  static {
209
198
  __name(this, "RequestService");
210
199
  }
@@ -253,7 +242,7 @@ var RequestService = class {
253
242
  }
254
243
  }
255
244
  return null;
256
- } catch (error) {
245
+ } catch (_error) {
257
246
  return null;
258
247
  }
259
248
  }
@@ -273,7 +262,7 @@ var RequestService = class {
273
262
  return this.request.headers || {};
274
263
  }
275
264
  };
276
- RequestService = _ts_decorate([
265
+ RequestService2 = _ts_decorate([
277
266
  (0, import_common.Injectable)({
278
267
  scope: import_common.Scope.REQUEST
279
268
  }),
@@ -282,7 +271,7 @@ RequestService = _ts_decorate([
282
271
  _ts_metadata("design:paramtypes", [
283
272
  typeof FastifyRequest === "undefined" ? Object : FastifyRequest
284
273
  ])
285
- ], RequestService);
274
+ ], RequestService2);
286
275
 
287
276
  // src/request/request.module.ts
288
277
  function _ts_decorate2(decorators, target, key, desc) {
@@ -301,30 +290,31 @@ RequestModule = _ts_decorate2([
301
290
  (0, import_common2.Global)(),
302
291
  (0, import_common2.Module)({
303
292
  providers: [
304
- RequestService
293
+ RequestService2
305
294
  ],
306
295
  exports: [
307
- RequestService
296
+ RequestService2
308
297
  ]
309
298
  })
310
299
  ], RequestModule);
311
300
 
312
301
  // src/auth/guards/vritti-auth.guard.ts
313
- var import_common4 = require("@nestjs/common");
314
- var import_config2 = require("@nestjs/config");
315
- var import_core2 = require("@nestjs/core");
316
- var import_jwt = require("@nestjs/jwt");
317
-
318
- // src/database/services/primary-database.service.ts
319
302
  var import_common3 = require("@nestjs/common");
320
- var import_pg = require("pg");
321
- var import_node_postgres = require("drizzle-orm/node-postgres");
322
- var import_drizzle_orm = require("drizzle-orm");
323
303
 
324
- // src/database/constants.ts
325
- var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
304
+ // src/auth/utils/token-hash.util.ts
305
+ var crypto = __toESM(require("crypto"), 1);
306
+ function hashToken(token) {
307
+ return crypto.createHash("sha256").update(token).digest("hex");
308
+ }
309
+ __name(hashToken, "hashToken");
310
+ function verifyTokenHash(token, expectedHash) {
311
+ const computedHash = hashToken(token);
312
+ if (computedHash.length !== expectedHash.length) return false;
313
+ return crypto.timingSafeEqual(Buffer.from(computedHash, "hex"), Buffer.from(expectedHash, "hex"));
314
+ }
315
+ __name(verifyTokenHash, "verifyTokenHash");
326
316
 
327
- // src/database/services/primary-database.service.ts
317
+ // src/auth/guards/vritti-auth.guard.ts
328
318
  function _ts_decorate3(decorators, target, key, desc) {
329
319
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
330
320
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -336,526 +326,693 @@ function _ts_metadata2(k, v) {
336
326
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
337
327
  }
338
328
  __name(_ts_metadata2, "_ts_metadata");
339
- function _ts_param2(paramIndex, decorator) {
340
- return function(target, key) {
341
- decorator(target, key, paramIndex);
342
- };
343
- }
344
- __name(_ts_param2, "_ts_param");
345
- var PrimaryDatabaseService = class _PrimaryDatabaseService {
329
+ var VrittiAuthGuard = class _VrittiAuthGuard {
346
330
  static {
347
- __name(this, "PrimaryDatabaseService");
331
+ __name(this, "VrittiAuthGuard");
348
332
  }
349
- options;
350
- logger = new import_common3.Logger(_PrimaryDatabaseService.name);
351
- /** PostgreSQL connection pool */
352
- pool = null;
353
- /** Drizzle database instance */
354
- db = null;
355
- /** In-memory cache: Map<tenantIdentifier, TenantConfig> */
356
- tenantConfigCache = /* @__PURE__ */ new Map();
357
- /** Cache TTL in milliseconds */
358
- cacheTTL;
359
- constructor(options) {
360
- this.options = options;
361
- this.cacheTTL = options.connectionCacheTTL || 3e5;
333
+ reflector;
334
+ _configService;
335
+ jwtService;
336
+ primaryDatabase;
337
+ requestService;
338
+ logger = new import_common3.Logger(_VrittiAuthGuard.name);
339
+ constructor(reflector, _configService, jwtService, primaryDatabase, requestService) {
340
+ this.reflector = reflector;
341
+ this._configService = _configService;
342
+ this.jwtService = jwtService;
343
+ this.primaryDatabase = primaryDatabase;
344
+ this.requestService = requestService;
362
345
  }
363
- async onModuleInit() {
364
- if (this.options.primaryDb) {
365
- await this.initializeDrizzleClient();
346
+ async canActivate(context) {
347
+ const request = context.switchToHttp().getRequest();
348
+ const isPublic = this.reflector.getAllAndOverride("isPublic", [
349
+ context.getHandler(),
350
+ context.getClass()
351
+ ]);
352
+ if (isPublic) {
353
+ this.logger.debug("Public endpoint detected, skipping authentication");
354
+ return true;
355
+ }
356
+ const isOnboarding = this.reflector.getAllAndOverride("isOnboarding", [
357
+ context.getHandler(),
358
+ context.getClass()
359
+ ]);
360
+ try {
361
+ const accessToken = this.requestService.getAccessToken();
362
+ if (!accessToken) {
363
+ this.logger.warn("Access token not found in Authorization header");
364
+ throw new import_common3.UnauthorizedException("Access token not found");
365
+ }
366
+ const decodedToken = this.jwtService.decode(accessToken);
367
+ if (!decodedToken) {
368
+ this.logger.warn("Failed to decode access token");
369
+ throw new import_common3.UnauthorizedException("Invalid token format");
370
+ }
371
+ if (isOnboarding) {
372
+ if (decodedToken.type !== "onboarding") {
373
+ this.logger.warn("Onboarding endpoint requires onboarding token");
374
+ throw new import_common3.UnauthorizedException("This endpoint requires an onboarding token");
375
+ }
376
+ const validatedToken2 = this.validateAccessToken(accessToken);
377
+ this.logger.debug("Onboarding token validated successfully");
378
+ this.validateRefreshTokenBinding(context, validatedToken2);
379
+ const userId2 = validatedToken2.userId;
380
+ request.user = {
381
+ id: userId2
382
+ };
383
+ return true;
384
+ }
385
+ if (decodedToken.type === "onboarding") {
386
+ this.logger.warn("Regular endpoint accessed with onboarding token");
387
+ throw new import_common3.UnauthorizedException("Onboarding tokens cannot access this endpoint");
388
+ }
389
+ const validatedToken = this.validateAccessToken(accessToken);
390
+ this.logger.debug("Access token validated successfully");
391
+ this.validateRefreshTokenBinding(context, validatedToken);
392
+ const userId = validatedToken.userId;
393
+ request.user = {
394
+ id: userId
395
+ };
396
+ const tenantIdentifier = this.requestService.getTenantIdentifier();
397
+ if (!tenantIdentifier) {
398
+ this.logger.warn("Tenant identifier not found in request");
399
+ throw new import_common3.UnauthorizedException("Tenant identifier not found");
400
+ }
401
+ this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
402
+ if (tenantIdentifier === "cloud") {
403
+ this.logger.debug("Platform admin access detected, skipping tenant database validation");
404
+ return true;
405
+ }
406
+ const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
407
+ if (!tenantInfo) {
408
+ this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
409
+ throw new import_common3.UnauthorizedException("Invalid tenant");
410
+ }
411
+ if (tenantInfo.status !== "ACTIVE") {
412
+ this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
413
+ throw new import_common3.UnauthorizedException(`Tenant is ${tenantInfo.status}`);
414
+ }
415
+ this.logger.debug(`Tenant validated: ${tenantInfo.subdomain} (${tenantInfo.type})`);
416
+ return true;
417
+ } catch (error) {
418
+ if (error instanceof import_common3.UnauthorizedException) {
419
+ throw error;
420
+ }
421
+ this.logger.error("Unexpected error in auth guard", error);
422
+ throw new import_common3.UnauthorizedException("Authentication failed");
366
423
  }
367
424
  }
368
425
  /**
369
- * Initialize connection to primary database using Drizzle
426
+ * Validate access token with proper expiry checks
427
+ * Throws UnauthorizedException if token is invalid or expired
370
428
  */
371
- async initializeDrizzleClient() {
429
+ validateAccessToken(token) {
372
430
  try {
373
- const databaseUrl = this.buildPrimaryDbUrl();
374
- this.pool = new import_pg.Pool({
375
- connectionString: databaseUrl,
376
- max: this.options.maxConnections || 10
377
- });
378
- this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
379
- this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
380
- this.db = (0, import_node_postgres.drizzle)({
381
- client: this.pool,
382
- schema: this.options.drizzleSchema,
383
- relations: this.options.drizzleRelations
384
- });
385
- this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
386
- await this.pool.query("SELECT 1");
387
- this.logger.log("Connected to primary database (tenant registry)");
431
+ const decoded = this.jwtService.verify(token);
432
+ this.logger.debug(`Access token decoded for user: ${decoded.userId}`);
433
+ if (decoded.exp) {
434
+ const expiryTime = decoded.exp * 1e3;
435
+ const currentTime = Date.now();
436
+ const timeRemaining = expiryTime - currentTime;
437
+ this.logger.debug(`Access token valid for ${Math.floor(timeRemaining / 1e3)} more seconds`);
438
+ }
439
+ return decoded;
388
440
  } catch (error) {
389
- this.logger.error("Failed to connect to primary database", error);
390
- throw new import_common3.InternalServerErrorException("Failed to initialize tenant registry");
441
+ if (error instanceof import_common3.UnauthorizedException) {
442
+ throw error;
443
+ }
444
+ const jwtError = error;
445
+ if (jwtError?.name === "TokenExpiredError") {
446
+ this.logger.warn(`Access token expired at: ${jwtError?.expiredAt}`);
447
+ throw new import_common3.UnauthorizedException("Access token has expired");
448
+ }
449
+ if (jwtError?.name === "JsonWebTokenError") {
450
+ this.logger.warn(`Access token verification failed: ${jwtError?.message}`);
451
+ throw new import_common3.UnauthorizedException("Invalid access token");
452
+ }
453
+ if (jwtError?.name === "NotBeforeError") {
454
+ this.logger.warn("Access token used before valid (nbf claim)");
455
+ throw new import_common3.UnauthorizedException("Access token not yet valid");
456
+ }
457
+ this.logger.error("Unexpected error validating access token", error);
458
+ throw new import_common3.UnauthorizedException("Access token validation failed");
391
459
  }
392
460
  }
393
461
  /**
394
- * Build connection URL from primary database properties
462
+ * Validate that the access token is bound to the refresh token in the cookie.
463
+ * This prevents token theft - a stolen access token is useless without the
464
+ * corresponding refresh token cookie.
465
+ *
466
+ * @param context - The execution context containing the request
467
+ * @param validatedToken - The decoded and validated JWT token
468
+ * @throws UnauthorizedException if token binding validation fails
395
469
  */
396
- buildPrimaryDbUrl() {
397
- if (!this.options.primaryDb) {
398
- throw new Error("Primary database configuration not provided");
470
+ validateRefreshTokenBinding(context, validatedToken) {
471
+ const config = getConfig();
472
+ if (!config.jwt.validateTokenBinding) {
473
+ this.logger.debug("Token binding validation is disabled");
474
+ return;
399
475
  }
400
- const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
401
- let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
402
- const params = new URLSearchParams();
403
- if (schema) {
404
- params.set("schema", schema);
476
+ if (!validatedToken.refreshTokenHash) {
477
+ this.logger.debug("Token does not contain refreshTokenHash, skipping binding validation");
478
+ return;
405
479
  }
406
- params.set("sslmode", sslMode);
407
- const queryString = params.toString();
408
- if (queryString) {
409
- url += `?${queryString}`;
480
+ const request = context.switchToHttp().getRequest();
481
+ const cookies = request.cookies || {};
482
+ const refreshToken = cookies[config.cookie.refreshCookieName];
483
+ if (!refreshToken) {
484
+ this.logger.warn("Session validation failed - refresh token cookie not found");
485
+ throw new import_common3.UnauthorizedException("Session validation failed");
410
486
  }
411
- this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
412
- return url;
413
- }
414
- /**
415
- * Mask password in connection URL for logging
416
- */
417
- maskPassword(url) {
418
- return url.replace(/:([^@]+)@/, ":****@");
487
+ if (!verifyTokenHash(refreshToken, validatedToken.refreshTokenHash)) {
488
+ this.logger.warn("Session validation failed - token binding mismatch");
489
+ throw new import_common3.UnauthorizedException("Session validation failed");
490
+ }
491
+ this.logger.debug("Token binding validated successfully");
419
492
  }
420
- /**
421
- * Get tenant configuration by identifier (ID or subdomain)
422
- *
423
- * @param tenantIdentifier Tenant ID or subdomain
424
- * @returns Tenant configuration or null if not found
425
- */
426
- async getTenantInfo(tenantIdentifier) {
427
- const cached = this.tenantConfigCache.get(tenantIdentifier);
428
- if (cached) {
429
- this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
430
- return cached;
431
- }
432
- try {
433
- if (!this.db) {
434
- throw new Error("Primary database client not initialized");
435
- }
436
- this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
437
- const schema = this.options.drizzleSchema;
438
- const { tenants, tenantDatabaseConfigs } = schema;
439
- const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, (0, import_drizzle_orm.eq)(tenants.id, tenantDatabaseConfigs.tenantId)).where((0, import_drizzle_orm.or)((0, import_drizzle_orm.eq)(tenants.id, tenantIdentifier), (0, import_drizzle_orm.eq)(tenants.subdomain, tenantIdentifier))).limit(1);
440
- if (!result.length) {
441
- this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
442
- return null;
443
- }
444
- const row = result[0];
445
- const tenant = row.tenants;
446
- const config = row.tenant_database_configs;
447
- if (tenant.status !== "ACTIVE") {
448
- this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
449
- return null;
450
- }
451
- const info = {
452
- id: tenant.id,
453
- subdomain: tenant.subdomain,
454
- type: tenant.dbType,
455
- status: tenant.status,
456
- // For SHARED tenants: schema name
457
- schemaName: config?.dbSchema || void 0,
458
- // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
459
- databaseName: config?.dbName || void 0,
460
- databaseHost: config?.dbHost || void 0,
461
- databasePort: config?.dbPort || void 0,
462
- databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
463
- databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
464
- databaseSslMode: config?.dbSslMode || void 0,
465
- connectionPoolSize: config?.connectionPoolSize || void 0
466
- };
467
- this.cacheInfo(info);
468
- return info;
469
- } catch (error) {
470
- this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
471
- throw new import_common3.InternalServerErrorException("Failed to resolve tenant");
472
- }
473
- }
474
- /**
475
- * Cache tenant information with TTL
476
- */
477
- cacheInfo(info) {
478
- this.tenantConfigCache.set(info.id, info);
479
- this.tenantConfigCache.set(info.subdomain, info);
480
- setTimeout(() => {
481
- this.tenantConfigCache.delete(info.id);
482
- this.tenantConfigCache.delete(info.subdomain);
483
- this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
484
- }, this.cacheTTL);
493
+ };
494
+ VrittiAuthGuard = _ts_decorate3([
495
+ (0, import_common3.Injectable)({
496
+ scope: import_common3.Scope.REQUEST
497
+ }),
498
+ _ts_metadata2("design:type", Function),
499
+ _ts_metadata2("design:paramtypes", [
500
+ typeof Reflector === "undefined" ? Object : Reflector,
501
+ typeof ConfigService === "undefined" ? Object : ConfigService,
502
+ typeof JwtService === "undefined" ? Object : JwtService,
503
+ typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
504
+ typeof RequestService === "undefined" ? Object : RequestService
505
+ ])
506
+ ], VrittiAuthGuard);
507
+
508
+ // src/auth/auth-config.module.ts
509
+ function _ts_decorate4(decorators, target, key, desc) {
510
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
511
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
512
+ 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;
513
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
514
+ }
515
+ __name(_ts_decorate4, "_ts_decorate");
516
+ var AuthConfigModule = class _AuthConfigModule {
517
+ static {
518
+ __name(this, "AuthConfigModule");
485
519
  }
486
520
  /**
487
- * Clear cached tenant information
521
+ * Register the auth module with async configuration
488
522
  *
489
- * Useful when tenant settings are updated and cache needs to be invalidated
523
+ * This method:
524
+ * 1. Configures JwtModule with JWT_SECRET from ConfigService
525
+ * 2. Provides VrittiAuthGuard globally (applies to all routes)
526
+ * 3. Exports JwtModule for use in other modules (e.g., for signing tokens)
490
527
  *
491
- * @param tenantIdentifier Tenant ID or subdomain
528
+ * @returns Dynamic module configuration
492
529
  */
493
- clearTenantCache(tenantIdentifier) {
494
- const config = this.tenantConfigCache.get(tenantIdentifier);
495
- if (config) {
496
- this.tenantConfigCache.delete(config.id);
497
- this.tenantConfigCache.delete(config.subdomain);
498
- this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
499
- }
530
+ static forRootAsync() {
531
+ return {
532
+ module: _AuthConfigModule,
533
+ imports: [
534
+ import_config3.ConfigModule,
535
+ RequestModule,
536
+ import_jwt.JwtModule.registerAsync({
537
+ imports: [
538
+ import_config3.ConfigModule
539
+ ],
540
+ inject: [
541
+ import_config3.ConfigService
542
+ ],
543
+ useFactory: /* @__PURE__ */ __name((config) => ({
544
+ secret: config.get("JWT_SECRET"),
545
+ signOptions: {
546
+ algorithm: "HS256"
547
+ }
548
+ }), "useFactory")
549
+ })
550
+ ],
551
+ providers: [
552
+ {
553
+ provide: import_core2.APP_GUARD,
554
+ useClass: VrittiAuthGuard
555
+ }
556
+ ],
557
+ exports: [
558
+ import_jwt.JwtModule
559
+ ]
560
+ };
500
561
  }
501
- /**
502
- * Clear all cached tenant configurations
503
- */
504
- clearAllCaches() {
505
- const size = this.tenantConfigCache.size;
506
- this.tenantConfigCache.clear();
507
- this.logger.log(`Cleared ${size} cached tenant configs`);
562
+ };
563
+ AuthConfigModule = _ts_decorate4([
564
+ (0, import_common4.Global)(),
565
+ (0, import_common4.Module)({})
566
+ ], AuthConfigModule);
567
+
568
+ // src/auth/decorators/onboarding.decorator.ts
569
+ var import_common5 = require("@nestjs/common");
570
+ var Onboarding = /* @__PURE__ */ __name(() => (0, import_common5.SetMetadata)("isOnboarding", true), "Onboarding");
571
+
572
+ // src/auth/decorators/public.decorator.ts
573
+ var import_common6 = require("@nestjs/common");
574
+ var Public = /* @__PURE__ */ __name(() => (0, import_common6.SetMetadata)("isPublic", true), "Public");
575
+
576
+ // src/database/database.module.ts
577
+ var import_common12 = require("@nestjs/common");
578
+ var import_core3 = require("@nestjs/core");
579
+
580
+ // src/database/constants.ts
581
+ var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
582
+
583
+ // src/database/interceptors/message-tenant-context.interceptor.ts
584
+ var import_common7 = require("@nestjs/common");
585
+ var import_operators = require("rxjs/operators");
586
+ function _ts_decorate5(decorators, target, key, desc) {
587
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
588
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
589
+ 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;
590
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
591
+ }
592
+ __name(_ts_decorate5, "_ts_decorate");
593
+ function _ts_metadata3(k, v) {
594
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
595
+ }
596
+ __name(_ts_metadata3, "_ts_metadata");
597
+ var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
598
+ static {
599
+ __name(this, "MessageTenantContextInterceptor");
508
600
  }
509
- /**
510
- * Get the Drizzle database instance for the primary database.
511
- * This is a synchronous property that returns the initialized Drizzle client.
512
- *
513
- * @returns Primary database Drizzle instance
514
- * @throws Error if primary database client is not initialized
515
- */
516
- get drizzleClient() {
517
- if (!this.db) {
518
- throw new Error("Primary database client not initialized");
519
- }
520
- return this.db;
601
+ tenantContext;
602
+ logger = new import_common7.Logger(_MessageTenantContextInterceptor.name);
603
+ constructor(tenantContext) {
604
+ this.tenantContext = tenantContext;
521
605
  }
522
- /**
523
- * Get the Drizzle schema
524
- */
525
- get schema() {
526
- return this.options.drizzleSchema;
606
+ intercept(context, next) {
607
+ const contextType = context.getType();
608
+ if (contextType === "rpc") {
609
+ const rpcContext = context.switchToRpc();
610
+ const payload = rpcContext.getData();
611
+ if (payload?.tenant) {
612
+ const tenant = payload.tenant;
613
+ this.logger.debug(`Setting tenant context from message: ${tenant.subdomain}`);
614
+ try {
615
+ this.tenantContext.setTenant(tenant);
616
+ this.logger.log(`Tenant context set: ${tenant.subdomain} (${tenant.type})`);
617
+ } catch (error) {
618
+ this.logger.error("Failed to set tenant context from message", error);
619
+ }
620
+ } else {
621
+ this.logger.warn("Message payload missing tenant information");
622
+ }
623
+ }
624
+ return next.handle().pipe((0, import_operators.tap)({
625
+ next: /* @__PURE__ */ __name(() => {
626
+ this.cleanupContext();
627
+ }, "next"),
628
+ error: /* @__PURE__ */ __name(() => {
629
+ this.cleanupContext();
630
+ }, "error"),
631
+ complete: /* @__PURE__ */ __name(() => {
632
+ this.cleanupContext();
633
+ }, "complete")
634
+ }));
527
635
  }
528
636
  /**
529
- * Decrypt database credentials
530
- *
531
- * Override this method to implement your encryption strategy
532
- *
533
- * @param encrypted Encrypted value
534
- * @returns Decrypted value
637
+ * Clean up tenant context after message is processed
535
638
  */
536
- decrypt(encrypted) {
537
- return encrypted;
538
- }
539
- async onModuleDestroy() {
540
- if (this.pool) {
541
- await this.pool.end();
542
- this.logger.log("Disconnected from primary database");
639
+ cleanupContext() {
640
+ if (this.tenantContext.hasTenant()) {
641
+ const tenant = this.tenantContext.getTenantIdSafe();
642
+ this.tenantContext.clearTenant();
643
+ this.logger.debug(`Cleaned up tenant context: ${tenant}`);
543
644
  }
544
645
  }
545
646
  };
546
- PrimaryDatabaseService = _ts_decorate3([
547
- (0, import_common3.Injectable)(),
548
- _ts_param2(0, (0, import_common3.Inject)(DATABASE_MODULE_OPTIONS)),
549
- _ts_metadata2("design:type", Function),
550
- _ts_metadata2("design:paramtypes", [
551
- typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
647
+ MessageTenantContextInterceptor = _ts_decorate5([
648
+ (0, import_common7.Injectable)({
649
+ scope: import_common7.Scope.REQUEST
650
+ }),
651
+ _ts_metadata3("design:type", Function),
652
+ _ts_metadata3("design:paramtypes", [
653
+ typeof TenantContextService === "undefined" ? Object : TenantContextService
552
654
  ])
553
- ], PrimaryDatabaseService);
655
+ ], MessageTenantContextInterceptor);
554
656
 
555
- // src/auth/guards/vritti-auth.guard.ts
556
- function _ts_decorate4(decorators, target, key, desc) {
657
+ // src/database/interceptors/tenant-context.interceptor.ts
658
+ var import_common8 = require("@nestjs/common");
659
+ function _ts_decorate6(decorators, target, key, desc) {
557
660
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
558
661
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
559
662
  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;
560
663
  return c > 3 && r && Object.defineProperty(target, key, r), r;
561
664
  }
562
- __name(_ts_decorate4, "_ts_decorate");
563
- function _ts_metadata3(k, v) {
665
+ __name(_ts_decorate6, "_ts_decorate");
666
+ function _ts_metadata4(k, v) {
564
667
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
565
668
  }
566
- __name(_ts_metadata3, "_ts_metadata");
567
- var VrittiAuthGuard = class _VrittiAuthGuard {
669
+ __name(_ts_metadata4, "_ts_metadata");
670
+ var TenantContextInterceptor = class _TenantContextInterceptor {
568
671
  static {
569
- __name(this, "VrittiAuthGuard");
672
+ __name(this, "TenantContextInterceptor");
570
673
  }
571
674
  reflector;
572
- configService;
573
- jwtService;
675
+ tenantContext;
574
676
  primaryDatabase;
575
677
  requestService;
576
- logger = new import_common4.Logger(_VrittiAuthGuard.name);
577
- constructor(reflector, configService, jwtService, primaryDatabase, requestService) {
678
+ logger = new import_common8.Logger(_TenantContextInterceptor.name);
679
+ constructor(reflector, tenantContext, primaryDatabase, requestService) {
578
680
  this.reflector = reflector;
579
- this.configService = configService;
580
- this.jwtService = jwtService;
681
+ this.tenantContext = tenantContext;
581
682
  this.primaryDatabase = primaryDatabase;
582
683
  this.requestService = requestService;
583
684
  }
584
- async canActivate(context) {
685
+ async intercept(context, next) {
585
686
  const request = context.switchToHttp().getRequest();
687
+ this.logger.debug(`Processing request: ${request.method} ${request.url}`);
586
688
  const isPublic = this.reflector.getAllAndOverride("isPublic", [
587
689
  context.getHandler(),
588
690
  context.getClass()
589
691
  ]);
590
- if (isPublic) {
591
- this.logger.debug("Public endpoint detected, skipping authentication");
592
- return true;
593
- }
594
- const isOnboarding = this.reflector.getAllAndOverride("isOnboarding", [
595
- context.getHandler(),
596
- context.getClass()
597
- ]);
598
692
  try {
599
- const accessToken = this.requestService.getAccessToken();
600
- if (!accessToken) {
601
- this.logger.warn("Access token not found in Authorization header");
602
- throw new import_common4.UnauthorizedException("Access token not found");
603
- }
604
- const decodedToken = this.jwtService.decode(accessToken);
605
- if (!decodedToken) {
606
- this.logger.warn("Failed to decode access token");
607
- throw new import_common4.UnauthorizedException("Invalid token format");
608
- }
609
- if (isOnboarding) {
610
- if (decodedToken.type !== "onboarding") {
611
- this.logger.warn("Onboarding endpoint requires onboarding token");
612
- throw new import_common4.UnauthorizedException("This endpoint requires an onboarding token");
613
- }
614
- const validatedToken2 = this.validateAccessToken(accessToken);
615
- this.logger.debug("Onboarding token validated successfully");
616
- this.validateRefreshTokenBinding(context, validatedToken2);
617
- const userId2 = validatedToken2.userId;
618
- request.user = {
619
- id: userId2
620
- };
621
- return true;
622
- }
623
- if (decodedToken.type === "onboarding") {
624
- this.logger.warn("Regular endpoint accessed with onboarding token");
625
- throw new import_common4.UnauthorizedException("Onboarding tokens cannot access this endpoint");
626
- }
627
- const validatedToken = this.validateAccessToken(accessToken);
628
- this.logger.debug("Access token validated successfully");
629
- this.validateRefreshTokenBinding(context, validatedToken);
630
- const userId = validatedToken.userId;
631
- request.user = {
632
- id: userId
633
- };
634
693
  const tenantIdentifier = this.requestService.getTenantIdentifier();
694
+ if (isPublic && !tenantIdentifier) {
695
+ this.logger.debug("Public endpoint without tenant identifier, skipping tenant context setup");
696
+ return next.handle();
697
+ }
635
698
  if (!tenantIdentifier) {
636
- this.logger.warn("Tenant identifier not found in request");
637
- throw new import_common4.UnauthorizedException("Tenant identifier not found");
699
+ throw new import_common8.UnauthorizedException("Tenant identifier not found in request");
638
700
  }
639
701
  this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
640
702
  if (tenantIdentifier === "cloud") {
641
- this.logger.debug("Platform admin access detected, skipping tenant database validation");
642
- return true;
703
+ this.logger.log("Cloud platform access detected, skipping tenant context setup");
704
+ return next.handle();
643
705
  }
644
706
  const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
645
707
  if (!tenantInfo) {
646
708
  this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
647
- throw new import_common4.UnauthorizedException("Invalid tenant");
709
+ throw new import_common8.UnauthorizedException("Invalid tenant");
648
710
  }
649
711
  if (tenantInfo.status !== "ACTIVE") {
650
712
  this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
651
- throw new import_common4.UnauthorizedException(`Tenant is ${tenantInfo.status}`);
652
- }
653
- this.logger.debug(`Tenant validated: ${tenantInfo.subdomain} (${tenantInfo.type})`);
654
- return true;
655
- } catch (error) {
656
- if (error instanceof import_common4.UnauthorizedException) {
657
- throw error;
658
- }
659
- this.logger.error("Unexpected error in auth guard", error);
660
- throw new import_common4.UnauthorizedException("Authentication failed");
661
- }
662
- }
663
- /**
664
- * Validate access token with proper expiry checks
665
- * Throws UnauthorizedException if token is invalid or expired
666
- */
667
- validateAccessToken(token) {
668
- try {
669
- const decoded = this.jwtService.verify(token);
670
- this.logger.debug(`Access token decoded for user: ${decoded.userId}`);
671
- if (decoded.exp) {
672
- const expiryTime = decoded.exp * 1e3;
673
- const currentTime = Date.now();
674
- const timeRemaining = expiryTime - currentTime;
675
- this.logger.debug(`Access token valid for ${Math.floor(timeRemaining / 1e3)} more seconds`);
713
+ throw new import_common8.UnauthorizedException(`Tenant is ${tenantInfo.status}`);
676
714
  }
677
- return decoded;
715
+ this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
716
+ this.tenantContext.setTenant(tenantInfo);
717
+ request.tenant = tenantInfo;
718
+ this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
678
719
  } catch (error) {
679
- if (error instanceof import_common4.UnauthorizedException) {
680
- throw error;
681
- }
682
- const jwtError = error;
683
- if (jwtError?.name === "TokenExpiredError") {
684
- this.logger.warn(`Access token expired at: ${jwtError?.expiredAt}`);
685
- throw new import_common4.UnauthorizedException("Access token has expired");
686
- }
687
- if (jwtError?.name === "JsonWebTokenError") {
688
- this.logger.warn(`Access token verification failed: ${jwtError?.message}`);
689
- throw new import_common4.UnauthorizedException("Invalid access token");
690
- }
691
- if (jwtError?.name === "NotBeforeError") {
692
- this.logger.warn("Access token used before valid (nbf claim)");
693
- throw new import_common4.UnauthorizedException("Access token not yet valid");
694
- }
695
- this.logger.error("Unexpected error validating access token", error);
696
- throw new import_common4.UnauthorizedException("Access token validation failed");
697
- }
698
- }
699
- /**
700
- * Validate that the access token is bound to the refresh token in the cookie.
701
- * This prevents token theft - a stolen access token is useless without the
702
- * corresponding refresh token cookie.
703
- *
704
- * @param context - The execution context containing the request
705
- * @param validatedToken - The decoded and validated JWT token
706
- * @throws UnauthorizedException if token binding validation fails
707
- */
708
- validateRefreshTokenBinding(context, validatedToken) {
709
- const config = getConfig();
710
- if (!config.jwt.validateTokenBinding) {
711
- this.logger.debug("Token binding validation is disabled");
712
- return;
713
- }
714
- if (!validatedToken.refreshTokenHash) {
715
- this.logger.debug("Token does not contain refreshTokenHash, skipping binding validation");
716
- return;
717
- }
718
- const request = context.switchToHttp().getRequest();
719
- const cookies = request.cookies || {};
720
- const refreshToken = cookies[config.cookie.refreshCookieName];
721
- if (!refreshToken) {
722
- this.logger.warn("Session validation failed - refresh token cookie not found");
723
- throw new import_common4.UnauthorizedException("Session validation failed");
724
- }
725
- if (!verifyTokenHash(refreshToken, validatedToken.refreshTokenHash)) {
726
- this.logger.warn("Session validation failed - token binding mismatch");
727
- throw new import_common4.UnauthorizedException("Session validation failed");
720
+ this.logger.error("Failed to set tenant context", error);
721
+ throw error;
728
722
  }
729
- this.logger.debug("Token binding validated successfully");
723
+ return next.handle();
730
724
  }
731
725
  };
732
- VrittiAuthGuard = _ts_decorate4([
733
- (0, import_common4.Injectable)({
734
- scope: import_common4.Scope.REQUEST
726
+ TenantContextInterceptor = _ts_decorate6([
727
+ (0, import_common8.Injectable)({
728
+ scope: import_common8.Scope.REQUEST
735
729
  }),
736
- _ts_metadata3("design:type", Function),
737
- _ts_metadata3("design:paramtypes", [
738
- typeof import_core2.Reflector === "undefined" ? Object : import_core2.Reflector,
739
- typeof import_config2.ConfigService === "undefined" ? Object : import_config2.ConfigService,
740
- typeof import_jwt.JwtService === "undefined" ? Object : import_jwt.JwtService,
730
+ _ts_metadata4("design:type", Function),
731
+ _ts_metadata4("design:paramtypes", [
732
+ typeof Reflector === "undefined" ? Object : Reflector,
733
+ typeof TenantContextService === "undefined" ? Object : TenantContextService,
741
734
  typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
742
735
  typeof RequestService === "undefined" ? Object : RequestService
743
736
  ])
744
- ], VrittiAuthGuard);
737
+ ], TenantContextInterceptor);
745
738
 
746
- // src/auth/auth-config.module.ts
747
- function _ts_decorate5(decorators, target, key, desc) {
739
+ // src/database/services/primary-database.service.ts
740
+ var import_common9 = require("@nestjs/common");
741
+ var import_drizzle_orm = require("drizzle-orm");
742
+ var import_node_postgres = require("drizzle-orm/node-postgres");
743
+ var import_pg = require("pg");
744
+ function _ts_decorate7(decorators, target, key, desc) {
748
745
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
749
746
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
750
747
  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;
751
748
  return c > 3 && r && Object.defineProperty(target, key, r), r;
752
749
  }
753
- __name(_ts_decorate5, "_ts_decorate");
754
- var AuthConfigModule = class _AuthConfigModule {
755
- static {
756
- __name(this, "AuthConfigModule");
757
- }
758
- /**
759
- * Register the auth module with async configuration
760
- *
761
- * This method:
762
- * 1. Configures JwtModule with JWT_SECRET from ConfigService
763
- * 2. Provides VrittiAuthGuard globally (applies to all routes)
764
- * 3. Exports JwtModule for use in other modules (e.g., for signing tokens)
765
- *
766
- * @returns Dynamic module configuration
767
- */
768
- static forRootAsync() {
769
- return {
770
- module: _AuthConfigModule,
771
- imports: [
772
- import_config4.ConfigModule,
773
- RequestModule,
774
- import_jwt2.JwtModule.registerAsync({
775
- imports: [
776
- import_config4.ConfigModule
777
- ],
778
- inject: [
779
- import_config4.ConfigService
780
- ],
781
- useFactory: /* @__PURE__ */ __name((config) => ({
782
- secret: config.get("JWT_SECRET"),
783
- signOptions: {
784
- algorithm: "HS256"
785
- }
786
- }), "useFactory")
787
- })
788
- ],
789
- providers: [
790
- {
791
- provide: import_core3.APP_GUARD,
792
- useClass: VrittiAuthGuard
793
- }
794
- ],
795
- exports: [
796
- import_jwt2.JwtModule
797
- ]
798
- };
799
- }
800
- };
801
- AuthConfigModule = _ts_decorate5([
802
- (0, import_common5.Global)(),
803
- (0, import_common5.Module)({})
804
- ], AuthConfigModule);
805
-
806
- // src/database/database.module.ts
807
- var import_common10 = require("@nestjs/common");
808
- var import_core5 = require("@nestjs/core");
809
-
810
- // src/database/interceptors/message-tenant-context.interceptor.ts
811
- var import_common7 = require("@nestjs/common");
812
- var import_operators = require("rxjs/operators");
813
-
814
- // src/database/services/tenant-context.service.ts
815
- var import_common6 = require("@nestjs/common");
816
- function _ts_decorate6(decorators, target, key, desc) {
817
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
818
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
819
- 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;
820
- return c > 3 && r && Object.defineProperty(target, key, r), r;
750
+ __name(_ts_decorate7, "_ts_decorate");
751
+ function _ts_metadata5(k, v) {
752
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
821
753
  }
822
- __name(_ts_decorate6, "_ts_decorate");
823
- var TenantContextService = class {
754
+ __name(_ts_metadata5, "_ts_metadata");
755
+ function _ts_param2(paramIndex, decorator) {
756
+ return function(target, key) {
757
+ decorator(target, key, paramIndex);
758
+ };
759
+ }
760
+ __name(_ts_param2, "_ts_param");
761
+ var PrimaryDatabaseService2 = class _PrimaryDatabaseService {
824
762
  static {
825
- __name(this, "TenantContextService");
763
+ __name(this, "PrimaryDatabaseService");
826
764
  }
827
- tenantInfo = null;
828
- /**
829
- * Set tenant information for this request/message
830
- *
831
- * This is typically called by:
832
- * - TenantContextInterceptor (for HTTP requests in gateway)
833
- * - MessageTenantContextInterceptor (for RabbitMQ messages in microservices)
834
- * - Manual context setup in message handlers
835
- *
836
- * @param tenantInfo Complete tenant information
837
- * @throws Error if tenant context is already set (prevents accidental overwrites)
838
- */
839
- setTenant(tenantInfo) {
840
- if (this.tenantInfo) {
841
- throw new Error("Tenant context already set for this request");
842
- }
843
- this.tenantInfo = tenantInfo;
765
+ options;
766
+ logger = new import_common9.Logger(_PrimaryDatabaseService.name);
767
+ /** PostgreSQL connection pool */
768
+ pool = null;
769
+ /** Drizzle database instance */
770
+ db = null;
771
+ /** In-memory cache: Map<tenantIdentifier, TenantConfig> */
772
+ tenantConfigCache = /* @__PURE__ */ new Map();
773
+ /** Cache TTL in milliseconds */
774
+ cacheTTL;
775
+ constructor(options) {
776
+ this.options = options;
777
+ this.cacheTTL = options.connectionCacheTTL || 3e5;
844
778
  }
845
- /**
846
- * Get tenant information for this request/message
847
- *
848
- * @returns Tenant information
849
- * @throws UnauthorizedException if tenant context hasn't been set
850
- */
851
- getTenant() {
852
- if (!this.tenantInfo) {
853
- throw new import_common6.UnauthorizedException("Tenant context not set");
779
+ async onModuleInit() {
780
+ if (this.options.primaryDb) {
781
+ await this.initializeDrizzleClient();
854
782
  }
855
- return this.tenantInfo;
856
783
  }
857
784
  /**
858
- * Check if tenant context has been set
785
+ * Initialize connection to primary database using Drizzle
786
+ */
787
+ async initializeDrizzleClient() {
788
+ try {
789
+ const databaseUrl = this.buildPrimaryDbUrl();
790
+ this.pool = new import_pg.Pool({
791
+ connectionString: databaseUrl,
792
+ max: this.options.maxConnections || 10
793
+ });
794
+ this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
795
+ this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
796
+ this.db = (0, import_node_postgres.drizzle)({
797
+ client: this.pool,
798
+ schema: this.options.drizzleSchema,
799
+ relations: this.options.drizzleRelations
800
+ });
801
+ this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
802
+ await this.pool.query("SELECT 1");
803
+ this.logger.log("Connected to primary database (tenant registry)");
804
+ } catch (error) {
805
+ this.logger.error("Failed to connect to primary database", error);
806
+ throw new import_common9.InternalServerErrorException("Failed to initialize tenant registry");
807
+ }
808
+ }
809
+ /**
810
+ * Build connection URL from primary database properties
811
+ */
812
+ buildPrimaryDbUrl() {
813
+ if (!this.options.primaryDb) {
814
+ throw new Error("Primary database configuration not provided");
815
+ }
816
+ const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
817
+ let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
818
+ const params = new URLSearchParams();
819
+ if (schema) {
820
+ params.set("schema", schema);
821
+ }
822
+ params.set("sslmode", sslMode);
823
+ const queryString = params.toString();
824
+ if (queryString) {
825
+ url += `?${queryString}`;
826
+ }
827
+ this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
828
+ return url;
829
+ }
830
+ /**
831
+ * Mask password in connection URL for logging
832
+ */
833
+ maskPassword(url) {
834
+ return url.replace(/:([^@]+)@/, ":****@");
835
+ }
836
+ /**
837
+ * Get tenant configuration by identifier (ID or subdomain)
838
+ *
839
+ * @param tenantIdentifier Tenant ID or subdomain
840
+ * @returns Tenant configuration or null if not found
841
+ */
842
+ async getTenantInfo(tenantIdentifier) {
843
+ const cached = this.tenantConfigCache.get(tenantIdentifier);
844
+ if (cached) {
845
+ this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
846
+ return cached;
847
+ }
848
+ try {
849
+ if (!this.db) {
850
+ throw new Error("Primary database client not initialized");
851
+ }
852
+ this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
853
+ const schema = this.options.drizzleSchema;
854
+ const { tenants, tenantDatabaseConfigs } = schema;
855
+ const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, (0, import_drizzle_orm.eq)(tenants.id, tenantDatabaseConfigs.tenantId)).where((0, import_drizzle_orm.or)((0, import_drizzle_orm.eq)(tenants.id, tenantIdentifier), (0, import_drizzle_orm.eq)(tenants.subdomain, tenantIdentifier))).limit(1);
856
+ if (!result.length) {
857
+ this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
858
+ return null;
859
+ }
860
+ const row = result[0];
861
+ const tenant = row.tenants;
862
+ const config = row.tenant_database_configs;
863
+ if (tenant.status !== "ACTIVE") {
864
+ this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
865
+ return null;
866
+ }
867
+ const info = {
868
+ id: tenant.id,
869
+ subdomain: tenant.subdomain,
870
+ type: tenant.dbType,
871
+ status: tenant.status,
872
+ // For SHARED tenants: schema name
873
+ schemaName: config?.dbSchema || void 0,
874
+ // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
875
+ databaseName: config?.dbName || void 0,
876
+ databaseHost: config?.dbHost || void 0,
877
+ databasePort: config?.dbPort || void 0,
878
+ databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
879
+ databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
880
+ databaseSslMode: config?.dbSslMode || void 0,
881
+ connectionPoolSize: config?.connectionPoolSize || void 0
882
+ };
883
+ this.cacheInfo(info);
884
+ return info;
885
+ } catch (error) {
886
+ this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
887
+ throw new import_common9.InternalServerErrorException("Failed to resolve tenant");
888
+ }
889
+ }
890
+ /**
891
+ * Cache tenant information with TTL
892
+ */
893
+ cacheInfo(info) {
894
+ this.tenantConfigCache.set(info.id, info);
895
+ this.tenantConfigCache.set(info.subdomain, info);
896
+ setTimeout(() => {
897
+ this.tenantConfigCache.delete(info.id);
898
+ this.tenantConfigCache.delete(info.subdomain);
899
+ this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
900
+ }, this.cacheTTL);
901
+ }
902
+ /**
903
+ * Clear cached tenant information
904
+ *
905
+ * Useful when tenant settings are updated and cache needs to be invalidated
906
+ *
907
+ * @param tenantIdentifier Tenant ID or subdomain
908
+ */
909
+ clearTenantCache(tenantIdentifier) {
910
+ const config = this.tenantConfigCache.get(tenantIdentifier);
911
+ if (config) {
912
+ this.tenantConfigCache.delete(config.id);
913
+ this.tenantConfigCache.delete(config.subdomain);
914
+ this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
915
+ }
916
+ }
917
+ /**
918
+ * Clear all cached tenant configurations
919
+ */
920
+ clearAllCaches() {
921
+ const size = this.tenantConfigCache.size;
922
+ this.tenantConfigCache.clear();
923
+ this.logger.log(`Cleared ${size} cached tenant configs`);
924
+ }
925
+ /**
926
+ * Get the Drizzle database instance for the primary database.
927
+ * This is a synchronous property that returns the initialized Drizzle client.
928
+ *
929
+ * @returns Primary database Drizzle instance
930
+ * @throws Error if primary database client is not initialized
931
+ */
932
+ get drizzleClient() {
933
+ if (!this.db) {
934
+ throw new Error("Primary database client not initialized");
935
+ }
936
+ return this.db;
937
+ }
938
+ /**
939
+ * Get the Drizzle schema
940
+ */
941
+ get schema() {
942
+ return this.options.drizzleSchema;
943
+ }
944
+ /**
945
+ * Decrypt database credentials
946
+ *
947
+ * Override this method to implement your encryption strategy
948
+ *
949
+ * @param encrypted Encrypted value
950
+ * @returns Decrypted value
951
+ */
952
+ decrypt(encrypted) {
953
+ return encrypted;
954
+ }
955
+ async onModuleDestroy() {
956
+ if (this.pool) {
957
+ await this.pool.end();
958
+ this.logger.log("Disconnected from primary database");
959
+ }
960
+ }
961
+ };
962
+ PrimaryDatabaseService2 = _ts_decorate7([
963
+ (0, import_common9.Injectable)(),
964
+ _ts_param2(0, (0, import_common9.Inject)(DATABASE_MODULE_OPTIONS)),
965
+ _ts_metadata5("design:type", Function),
966
+ _ts_metadata5("design:paramtypes", [
967
+ typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
968
+ ])
969
+ ], PrimaryDatabaseService2);
970
+
971
+ // src/database/services/tenant-context.service.ts
972
+ var import_common10 = require("@nestjs/common");
973
+ function _ts_decorate8(decorators, target, key, desc) {
974
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
975
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
976
+ 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;
977
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
978
+ }
979
+ __name(_ts_decorate8, "_ts_decorate");
980
+ var TenantContextService2 = class {
981
+ static {
982
+ __name(this, "TenantContextService");
983
+ }
984
+ tenantInfo = null;
985
+ /**
986
+ * Set tenant information for this request/message
987
+ *
988
+ * This is typically called by:
989
+ * - TenantContextInterceptor (for HTTP requests in gateway)
990
+ * - MessageTenantContextInterceptor (for RabbitMQ messages in microservices)
991
+ * - Manual context setup in message handlers
992
+ *
993
+ * @param tenantInfo Complete tenant information
994
+ * @throws Error if tenant context is already set (prevents accidental overwrites)
995
+ */
996
+ setTenant(tenantInfo) {
997
+ if (this.tenantInfo) {
998
+ throw new Error("Tenant context already set for this request");
999
+ }
1000
+ this.tenantInfo = tenantInfo;
1001
+ }
1002
+ /**
1003
+ * Get tenant information for this request/message
1004
+ *
1005
+ * @returns Tenant information
1006
+ * @throws UnauthorizedException if tenant context hasn't been set
1007
+ */
1008
+ getTenant() {
1009
+ if (!this.tenantInfo) {
1010
+ throw new import_common10.UnauthorizedException("Tenant context not set");
1011
+ }
1012
+ return this.tenantInfo;
1013
+ }
1014
+ /**
1015
+ * Check if tenant context has been set
859
1016
  *
860
1017
  * @returns true if tenant context is available
861
1018
  */
@@ -891,195 +1048,40 @@ var TenantContextService = class {
891
1048
  return this.tenantInfo?.subdomain ?? null;
892
1049
  }
893
1050
  };
894
- TenantContextService = _ts_decorate6([
895
- (0, import_common6.Injectable)({
896
- scope: import_common6.Scope.REQUEST
1051
+ TenantContextService2 = _ts_decorate8([
1052
+ (0, import_common10.Injectable)({
1053
+ scope: import_common10.Scope.REQUEST
897
1054
  })
898
- ], TenantContextService);
1055
+ ], TenantContextService2);
899
1056
 
900
- // src/database/interceptors/message-tenant-context.interceptor.ts
901
- function _ts_decorate7(decorators, target, key, desc) {
1057
+ // src/database/services/tenant-database.service.ts
1058
+ var import_common11 = require("@nestjs/common");
1059
+ var import_node_postgres2 = require("drizzle-orm/node-postgres");
1060
+ var import_pg2 = require("pg");
1061
+ function _ts_decorate9(decorators, target, key, desc) {
902
1062
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
903
1063
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
904
1064
  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;
905
1065
  return c > 3 && r && Object.defineProperty(target, key, r), r;
906
1066
  }
907
- __name(_ts_decorate7, "_ts_decorate");
908
- function _ts_metadata4(k, v) {
1067
+ __name(_ts_decorate9, "_ts_decorate");
1068
+ function _ts_metadata6(k, v) {
909
1069
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
910
1070
  }
911
- __name(_ts_metadata4, "_ts_metadata");
912
- var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
1071
+ __name(_ts_metadata6, "_ts_metadata");
1072
+ function _ts_param3(paramIndex, decorator) {
1073
+ return function(target, key) {
1074
+ decorator(target, key, paramIndex);
1075
+ };
1076
+ }
1077
+ __name(_ts_param3, "_ts_param");
1078
+ var TenantDatabaseService = class _TenantDatabaseService {
913
1079
  static {
914
- __name(this, "MessageTenantContextInterceptor");
1080
+ __name(this, "TenantDatabaseService");
915
1081
  }
1082
+ options;
916
1083
  tenantContext;
917
- logger = new import_common7.Logger(_MessageTenantContextInterceptor.name);
918
- constructor(tenantContext) {
919
- this.tenantContext = tenantContext;
920
- }
921
- intercept(context, next) {
922
- const contextType = context.getType();
923
- if (contextType === "rpc") {
924
- const rpcContext = context.switchToRpc();
925
- const payload = rpcContext.getData();
926
- if (payload && payload.tenant) {
927
- const tenant = payload.tenant;
928
- this.logger.debug(`Setting tenant context from message: ${tenant.subdomain}`);
929
- try {
930
- this.tenantContext.setTenant(tenant);
931
- this.logger.log(`Tenant context set: ${tenant.subdomain} (${tenant.type})`);
932
- } catch (error) {
933
- this.logger.error("Failed to set tenant context from message", error);
934
- }
935
- } else {
936
- this.logger.warn("Message payload missing tenant information");
937
- }
938
- }
939
- return next.handle().pipe((0, import_operators.tap)({
940
- next: /* @__PURE__ */ __name(() => {
941
- this.cleanupContext();
942
- }, "next"),
943
- error: /* @__PURE__ */ __name(() => {
944
- this.cleanupContext();
945
- }, "error"),
946
- complete: /* @__PURE__ */ __name(() => {
947
- this.cleanupContext();
948
- }, "complete")
949
- }));
950
- }
951
- /**
952
- * Clean up tenant context after message is processed
953
- */
954
- cleanupContext() {
955
- if (this.tenantContext.hasTenant()) {
956
- const tenant = this.tenantContext.getTenantIdSafe();
957
- this.tenantContext.clearTenant();
958
- this.logger.debug(`Cleaned up tenant context: ${tenant}`);
959
- }
960
- }
961
- };
962
- MessageTenantContextInterceptor = _ts_decorate7([
963
- (0, import_common7.Injectable)({
964
- scope: import_common7.Scope.REQUEST
965
- }),
966
- _ts_metadata4("design:type", Function),
967
- _ts_metadata4("design:paramtypes", [
968
- typeof TenantContextService === "undefined" ? Object : TenantContextService
969
- ])
970
- ], MessageTenantContextInterceptor);
971
-
972
- // src/database/interceptors/tenant-context.interceptor.ts
973
- var import_common8 = require("@nestjs/common");
974
- var import_core4 = require("@nestjs/core");
975
- function _ts_decorate8(decorators, target, key, desc) {
976
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
977
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
978
- 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;
979
- return c > 3 && r && Object.defineProperty(target, key, r), r;
980
- }
981
- __name(_ts_decorate8, "_ts_decorate");
982
- function _ts_metadata5(k, v) {
983
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
984
- }
985
- __name(_ts_metadata5, "_ts_metadata");
986
- var TenantContextInterceptor = class _TenantContextInterceptor {
987
- static {
988
- __name(this, "TenantContextInterceptor");
989
- }
990
- reflector;
991
- tenantContext;
992
- primaryDatabase;
993
- requestService;
994
- logger = new import_common8.Logger(_TenantContextInterceptor.name);
995
- constructor(reflector, tenantContext, primaryDatabase, requestService) {
996
- this.reflector = reflector;
997
- this.tenantContext = tenantContext;
998
- this.primaryDatabase = primaryDatabase;
999
- this.requestService = requestService;
1000
- }
1001
- async intercept(context, next) {
1002
- const request = context.switchToHttp().getRequest();
1003
- this.logger.debug(`Processing request: ${request.method} ${request.url}`);
1004
- const isPublic = this.reflector.getAllAndOverride("isPublic", [
1005
- context.getHandler(),
1006
- context.getClass()
1007
- ]);
1008
- try {
1009
- const tenantIdentifier = this.requestService.getTenantIdentifier();
1010
- if (isPublic && !tenantIdentifier) {
1011
- this.logger.debug("Public endpoint without tenant identifier, skipping tenant context setup");
1012
- return next.handle();
1013
- }
1014
- if (!tenantIdentifier) {
1015
- throw new import_common8.UnauthorizedException("Tenant identifier not found in request");
1016
- }
1017
- this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
1018
- if (tenantIdentifier === "cloud") {
1019
- this.logger.log("Cloud platform access detected, skipping tenant context setup");
1020
- return next.handle();
1021
- }
1022
- const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
1023
- if (!tenantInfo) {
1024
- this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
1025
- throw new import_common8.UnauthorizedException("Invalid tenant");
1026
- }
1027
- if (tenantInfo.status !== "ACTIVE") {
1028
- this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
1029
- throw new import_common8.UnauthorizedException(`Tenant is ${tenantInfo.status}`);
1030
- }
1031
- this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
1032
- this.tenantContext.setTenant(tenantInfo);
1033
- request.tenant = tenantInfo;
1034
- this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
1035
- } catch (error) {
1036
- this.logger.error("Failed to set tenant context", error);
1037
- throw error;
1038
- }
1039
- return next.handle();
1040
- }
1041
- };
1042
- TenantContextInterceptor = _ts_decorate8([
1043
- (0, import_common8.Injectable)({
1044
- scope: import_common8.Scope.REQUEST
1045
- }),
1046
- _ts_metadata5("design:type", Function),
1047
- _ts_metadata5("design:paramtypes", [
1048
- typeof import_core4.Reflector === "undefined" ? Object : import_core4.Reflector,
1049
- typeof TenantContextService === "undefined" ? Object : TenantContextService,
1050
- typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
1051
- typeof RequestService === "undefined" ? Object : RequestService
1052
- ])
1053
- ], TenantContextInterceptor);
1054
-
1055
- // src/database/services/tenant-database.service.ts
1056
- var import_common9 = require("@nestjs/common");
1057
- var import_pg2 = require("pg");
1058
- var import_node_postgres2 = require("drizzle-orm/node-postgres");
1059
- function _ts_decorate9(decorators, target, key, desc) {
1060
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1061
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1062
- 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;
1063
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1064
- }
1065
- __name(_ts_decorate9, "_ts_decorate");
1066
- function _ts_metadata6(k, v) {
1067
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1068
- }
1069
- __name(_ts_metadata6, "_ts_metadata");
1070
- function _ts_param3(paramIndex, decorator) {
1071
- return function(target, key) {
1072
- decorator(target, key, paramIndex);
1073
- };
1074
- }
1075
- __name(_ts_param3, "_ts_param");
1076
- var TenantDatabaseService = class _TenantDatabaseService {
1077
- static {
1078
- __name(this, "TenantDatabaseService");
1079
- }
1080
- options;
1081
- tenantContext;
1082
- logger = new import_common9.Logger(_TenantDatabaseService.name);
1084
+ logger = new import_common11.Logger(_TenantDatabaseService.name);
1083
1085
  /** Connection pool: Map<cacheKey, TenantConnection> */
1084
1086
  clients = /* @__PURE__ */ new Map();
1085
1087
  /** Track last usage time for idle connection cleanup */
@@ -1156,7 +1158,7 @@ var TenantDatabaseService = class _TenantDatabaseService {
1156
1158
  };
1157
1159
  } catch (error) {
1158
1160
  this.logger.error(`Failed to create database connection for tenant: ${tenant.subdomain}`, error);
1159
- throw new import_common9.InternalServerErrorException("Failed to connect to tenant database");
1161
+ throw new import_common11.InternalServerErrorException("Failed to connect to tenant database");
1160
1162
  }
1161
1163
  }
1162
1164
  /**
@@ -1249,8 +1251,8 @@ var TenantDatabaseService = class _TenantDatabaseService {
1249
1251
  }
1250
1252
  };
1251
1253
  TenantDatabaseService = _ts_decorate9([
1252
- (0, import_common9.Injectable)(),
1253
- _ts_param3(0, (0, import_common9.Inject)(DATABASE_MODULE_OPTIONS)),
1254
+ (0, import_common11.Injectable)(),
1255
+ _ts_param3(0, (0, import_common11.Inject)(DATABASE_MODULE_OPTIONS)),
1254
1256
  _ts_metadata6("design:type", Function),
1255
1257
  _ts_metadata6("design:paramtypes", [
1256
1258
  typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions,
@@ -1298,7 +1300,7 @@ var DatabaseModule = class _DatabaseModule {
1298
1300
  * })
1299
1301
  */
1300
1302
  static forServer(options) {
1301
- return this.createDynamicModule(options, "server");
1303
+ return _DatabaseModule.createDynamicModule(options, "server");
1302
1304
  }
1303
1305
  /**
1304
1306
  * Configure DatabaseModule for Microservice/Messaging mode (RabbitMQ workers)
@@ -1320,7 +1322,7 @@ var DatabaseModule = class _DatabaseModule {
1320
1322
  * })
1321
1323
  */
1322
1324
  static forMicroservice(options) {
1323
- return this.createDynamicModule(options, "microservice");
1325
+ return _DatabaseModule.createDynamicModule(options, "microservice");
1324
1326
  }
1325
1327
  /**
1326
1328
  * Internal helper to create dynamic module with conditional interceptor registration
@@ -1337,18 +1339,18 @@ var DatabaseModule = class _DatabaseModule {
1337
1339
  };
1338
1340
  const providers = [
1339
1341
  asyncProvider,
1340
- TenantContextService,
1341
- PrimaryDatabaseService,
1342
+ TenantContextService2,
1343
+ PrimaryDatabaseService2,
1342
1344
  TenantDatabaseService
1343
1345
  ];
1344
1346
  if (mode === "server") {
1345
1347
  providers.push({
1346
- provide: import_core5.APP_INTERCEPTOR,
1348
+ provide: import_core3.APP_INTERCEPTOR,
1347
1349
  useClass: TenantContextInterceptor
1348
1350
  });
1349
1351
  } else {
1350
1352
  providers.push({
1351
- provide: import_core5.APP_INTERCEPTOR,
1353
+ provide: import_core3.APP_INTERCEPTOR,
1352
1354
  useClass: MessageTenantContextInterceptor
1353
1355
  });
1354
1356
  }
@@ -1360,20 +1362,31 @@ var DatabaseModule = class _DatabaseModule {
1360
1362
  providers,
1361
1363
  exports: [
1362
1364
  TenantDatabaseService,
1363
- TenantContextService,
1364
- PrimaryDatabaseService,
1365
+ TenantContextService2,
1366
+ PrimaryDatabaseService2,
1365
1367
  asyncProvider
1366
1368
  ]
1367
1369
  };
1368
1370
  }
1369
1371
  };
1370
1372
  DatabaseModule = _ts_decorate10([
1371
- (0, import_common10.Global)(),
1372
- (0, import_common10.Module)({})
1373
+ (0, import_common12.Global)(),
1374
+ (0, import_common12.Module)({})
1373
1375
  ], DatabaseModule);
1374
1376
 
1377
+ // src/database/decorators/tenant.decorator.ts
1378
+ var import_common13 = require("@nestjs/common");
1379
+ var Tenant = (0, import_common13.createParamDecorator)((_data, ctx) => {
1380
+ const request = ctx.switchToHttp().getRequest();
1381
+ const tenantContext = request.app?.get?.(TenantContextService2);
1382
+ if (!tenantContext) {
1383
+ throw new Error("TenantContextService not found.");
1384
+ }
1385
+ return tenantContext.getTenant();
1386
+ });
1387
+
1375
1388
  // src/database/repositories/primary-base.repository.ts
1376
- var import_common11 = require("@nestjs/common");
1389
+ var import_common14 = require("@nestjs/common");
1377
1390
  var import_drizzle_orm2 = require("drizzle-orm");
1378
1391
  function snakeToCamel(str) {
1379
1392
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
@@ -1444,7 +1457,7 @@ var PrimaryBaseRepository = class {
1444
1457
  this.table = table;
1445
1458
  const dbTableName = (0, import_drizzle_orm2.getTableName)(table);
1446
1459
  this.tableName = snakeToCamel(dbTableName);
1447
- this.logger = new import_common11.Logger(this.constructor.name);
1460
+ this.logger = new import_common14.Logger(this.constructor.name);
1448
1461
  this.logger.debug(`Initialized ${this.constructor.name}`);
1449
1462
  this.logger.debug(`Table name: '${dbTableName}' -> query key: '${this.tableName}'`);
1450
1463
  }
@@ -1684,7 +1697,7 @@ var PrimaryBaseRepository = class {
1684
1697
  };
1685
1698
 
1686
1699
  // src/database/repositories/tenant-base.repository.ts
1687
- var import_common12 = require("@nestjs/common");
1700
+ var import_common15 = require("@nestjs/common");
1688
1701
  var import_drizzle_orm3 = require("drizzle-orm");
1689
1702
  var TenantBaseRepository = class {
1690
1703
  static {
@@ -1741,7 +1754,7 @@ var TenantBaseRepository = class {
1741
1754
  this.database = database;
1742
1755
  this.table = table;
1743
1756
  this.tableName = (0, import_drizzle_orm3.getTableName)(table);
1744
- this.logger = new import_common12.Logger(this.constructor.name);
1757
+ this.logger = new import_common15.Logger(this.constructor.name);
1745
1758
  this.logger.debug(`Initialized ${this.constructor.name}`);
1746
1759
  }
1747
1760
  /**
@@ -1973,424 +1986,282 @@ var TenantBaseRepository = class {
1973
1986
  }
1974
1987
  };
1975
1988
 
1976
- // src/database/decorators/tenant.decorator.ts
1977
- var import_common13 = require("@nestjs/common");
1978
- var Tenant = (0, import_common13.createParamDecorator)((data, ctx) => {
1979
- const request = ctx.switchToHttp().getRequest();
1980
- const tenantContext = request.app?.get?.(TenantContextService);
1981
- if (!tenantContext) {
1982
- throw new Error("TenantContextService not found.");
1983
- }
1984
- return tenantContext.getTenant();
1985
- });
1986
-
1987
- // src/auth/decorators/onboarding.decorator.ts
1988
- var import_common14 = require("@nestjs/common");
1989
- var Onboarding = /* @__PURE__ */ __name(() => (0, import_common14.SetMetadata)("isOnboarding", true), "Onboarding");
1990
-
1991
- // src/auth/decorators/public.decorator.ts
1992
- var import_common15 = require("@nestjs/common");
1993
- var Public = /* @__PURE__ */ __name(() => (0, import_common15.SetMetadata)("isPublic", true), "Public");
1994
-
1995
- // src/http/http.module.ts
1989
+ // src/exceptions/bad-gateway.exception.ts
1996
1990
  var import_common17 = require("@nestjs/common");
1997
1991
 
1998
- // src/http/guards/csrf.guard.ts
1992
+ // src/exceptions/base-field.exception.ts
1999
1993
  var import_common16 = require("@nestjs/common");
2000
- var import_core6 = require("@nestjs/core");
2001
- function _ts_decorate11(decorators, target, key, desc) {
2002
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2003
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2004
- 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;
2005
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2006
- }
2007
- __name(_ts_decorate11, "_ts_decorate");
2008
- function _ts_metadata7(k, v) {
2009
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2010
- }
2011
- __name(_ts_metadata7, "_ts_metadata");
2012
- var CsrfGuard = class _CsrfGuard {
1994
+ var BaseFieldException = class extends import_common16.HttpException {
2013
1995
  static {
2014
- __name(this, "CsrfGuard");
2015
- }
2016
- reflector;
2017
- logger = new import_common16.Logger(_CsrfGuard.name);
2018
- constructor(reflector) {
2019
- this.reflector = reflector;
1996
+ __name(this, "BaseFieldException");
2020
1997
  }
2021
- async canActivate(context) {
2022
- const request = context.switchToHttp().getRequest();
2023
- const reply = context.switchToHttp().getResponse();
2024
- const safeMethods = [
2025
- "GET",
2026
- "HEAD",
2027
- "OPTIONS"
2028
- ];
2029
- if (safeMethods.includes(request.method)) {
2030
- return true;
2031
- }
2032
- try {
2033
- const fastifyInstance = request.server;
2034
- if (!fastifyInstance.csrfProtection) {
2035
- this.logger.error("CSRF protection plugin not found. Ensure @fastify/csrf-protection is registered.");
2036
- throw new import_common16.ForbiddenException("CSRF protection not configured");
2037
- }
2038
- await new Promise((resolve, reject) => {
2039
- fastifyInstance.csrfProtection(request, reply, (err) => {
2040
- if (err) {
2041
- reject(err);
2042
- } else {
2043
- resolve();
2044
- }
2045
- });
2046
- });
2047
- this.logger.debug(`CSRF validation successful for ${request.method} ${request.url}`);
2048
- return true;
2049
- } catch (error) {
2050
- this.logger.warn(`CSRF validation failed for ${request.method} ${request.url}: ${error instanceof Error ? error.message : "Unknown error"}`);
2051
- throw new import_common16.ForbiddenException({
2052
- errors: [
2053
- {
2054
- field: "csrf",
2055
- message: "Invalid or missing CSRF token"
2056
- }
2057
- ],
2058
- message: "CSRF validation failed"
2059
- });
1998
+ constructor(statusOrMessageOrErrors, messageOrStatus, statusOrDetail, detail) {
1999
+ let errors;
2000
+ let httpStatus;
2001
+ let finalDetail;
2002
+ if (Array.isArray(statusOrMessageOrErrors)) {
2003
+ errors = statusOrMessageOrErrors;
2004
+ httpStatus = messageOrStatus || import_common16.HttpStatus.BAD_REQUEST;
2005
+ finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
2006
+ } else if (typeof statusOrMessageOrErrors === "string" && typeof messageOrStatus === "string") {
2007
+ errors = [
2008
+ {
2009
+ field: statusOrMessageOrErrors,
2010
+ message: messageOrStatus
2011
+ }
2012
+ ];
2013
+ httpStatus = statusOrDetail;
2014
+ finalDetail = detail;
2015
+ } else if (typeof statusOrMessageOrErrors === "string") {
2016
+ errors = [
2017
+ {
2018
+ message: statusOrMessageOrErrors
2019
+ }
2020
+ ];
2021
+ httpStatus = messageOrStatus;
2022
+ finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
2023
+ } else {
2024
+ errors = [
2025
+ {
2026
+ message: "An error occurred"
2027
+ }
2028
+ ];
2029
+ httpStatus = statusOrMessageOrErrors;
2030
+ finalDetail = void 0;
2060
2031
  }
2032
+ const response = finalDetail !== void 0 ? {
2033
+ errors,
2034
+ detail: finalDetail
2035
+ } : {
2036
+ errors
2037
+ };
2038
+ super(response, httpStatus);
2061
2039
  }
2062
2040
  };
2063
- CsrfGuard = _ts_decorate11([
2064
- (0, import_common16.Injectable)(),
2065
- _ts_metadata7("design:type", Function),
2066
- _ts_metadata7("design:paramtypes", [
2067
- typeof import_core6.Reflector === "undefined" ? Object : import_core6.Reflector
2068
- ])
2069
- ], CsrfGuard);
2070
2041
 
2071
- // src/http/http.module.ts
2072
- function _ts_decorate12(decorators, target, key, desc) {
2073
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2074
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2075
- 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;
2076
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2077
- }
2078
- __name(_ts_decorate12, "_ts_decorate");
2079
- var HttpModule = class {
2042
+ // src/exceptions/bad-gateway.exception.ts
2043
+ var BadGatewayException = class extends BaseFieldException {
2080
2044
  static {
2081
- __name(this, "HttpModule");
2045
+ __name(this, "BadGatewayException");
2046
+ }
2047
+ constructor(messageOrField, fieldMessageOrDetail, detail) {
2048
+ if (Array.isArray(messageOrField)) {
2049
+ super(messageOrField, import_common17.HttpStatus.BAD_GATEWAY, fieldMessageOrDetail);
2050
+ } else if (detail !== void 0) {
2051
+ super(messageOrField, fieldMessageOrDetail, import_common17.HttpStatus.BAD_GATEWAY, detail);
2052
+ } else if (fieldMessageOrDetail) {
2053
+ super(messageOrField, fieldMessageOrDetail, import_common17.HttpStatus.BAD_GATEWAY);
2054
+ } else {
2055
+ super(messageOrField, import_common17.HttpStatus.BAD_GATEWAY);
2056
+ }
2082
2057
  }
2083
2058
  };
2084
- HttpModule = _ts_decorate12([
2085
- (0, import_common17.Module)({
2086
- providers: [
2087
- CsrfGuard
2088
- ],
2089
- exports: [
2090
- CsrfGuard
2091
- ]
2092
- })
2093
- ], HttpModule);
2094
2059
 
2095
- // src/filters/http-exception.filter.ts
2060
+ // src/exceptions/bad-request.exception.ts
2096
2061
  var import_common18 = require("@nestjs/common");
2097
- function _ts_decorate13(decorators, target, key, desc) {
2098
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2099
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2100
- 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;
2101
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2102
- }
2103
- __name(_ts_decorate13, "_ts_decorate");
2104
- function getHttpStatusTitle(status) {
2105
- const enumKey = Object.entries(import_common18.HttpStatus).find(([key, value]) => value === status && isNaN(Number(key)))?.[0];
2106
- if (!enumKey) {
2107
- return "Error";
2108
- }
2109
- return enumKey.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
2110
- }
2111
- __name(getHttpStatusTitle, "getHttpStatusTitle");
2112
- var HttpExceptionFilter = class _HttpExceptionFilter {
2062
+ var BadRequestException = class extends BaseFieldException {
2113
2063
  static {
2114
- __name(this, "HttpExceptionFilter");
2064
+ __name(this, "BadRequestException");
2115
2065
  }
2116
- logger = new import_common18.Logger(_HttpExceptionFilter.name);
2117
- catch(exception, host) {
2118
- const ctx = host.switchToHttp();
2119
- const response = ctx.getResponse();
2120
- let status = import_common18.HttpStatus.INTERNAL_SERVER_ERROR;
2121
- let errors = [];
2122
- let detail = "Internal server error";
2123
- if (exception instanceof import_common18.HttpException) {
2124
- status = exception.getStatus();
2125
- const exceptionResponse = exception.getResponse();
2126
- if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
2127
- const responseObj = exceptionResponse;
2128
- if ("errors" in responseObj && Array.isArray(responseObj.errors)) {
2129
- errors = responseObj.errors;
2130
- detail = ("detail" in responseObj ? responseObj.detail : void 0) || exception.message;
2131
- } else if ("message" in responseObj && Array.isArray(responseObj.message)) {
2132
- errors = responseObj.message.map((msg) => {
2133
- if (typeof msg === "object" && "property" in msg && "constraints" in msg) {
2134
- const constraintValues = Object.values(msg.constraints);
2135
- return {
2136
- field: msg.property,
2137
- message: constraintValues[0] ?? "Validation failed"
2138
- };
2139
- }
2140
- return {
2141
- message: typeof msg === "string" ? msg : JSON.stringify(msg)
2142
- };
2143
- });
2144
- detail = "Validation failed";
2145
- } else if ("message" in responseObj) {
2146
- const message = responseObj.message;
2147
- errors = [
2148
- {
2149
- message: Array.isArray(message) ? message.join(", ") : message
2150
- }
2151
- ];
2152
- detail = ("error" in responseObj ? responseObj.error : void 0) || exception.message;
2153
- }
2154
- } else if (typeof exceptionResponse === "string") {
2155
- errors = [
2156
- {
2157
- message: exceptionResponse
2158
- }
2159
- ];
2160
- detail = exceptionResponse;
2161
- }
2066
+ constructor(messageOrField, fieldMessageOrDetail, detail) {
2067
+ if (Array.isArray(messageOrField)) {
2068
+ super(messageOrField, import_common18.HttpStatus.BAD_REQUEST, fieldMessageOrDetail);
2069
+ } else if (detail !== void 0) {
2070
+ super(messageOrField, fieldMessageOrDetail, import_common18.HttpStatus.BAD_REQUEST, detail);
2071
+ } else if (fieldMessageOrDetail) {
2072
+ super(messageOrField, fieldMessageOrDetail, import_common18.HttpStatus.BAD_REQUEST);
2162
2073
  } else {
2163
- const errorMessage = exception instanceof Error ? exception.message : "Unknown error";
2164
- const stack = exception instanceof Error ? exception.stack : void 0;
2165
- this.logger.error(`Unexpected error: ${errorMessage}`, stack);
2166
- errors = [
2167
- {
2168
- message: "An unexpected error occurred"
2169
- }
2170
- ];
2074
+ super(messageOrField, import_common18.HttpStatus.BAD_REQUEST);
2171
2075
  }
2172
- const problemDetails = {
2173
- title: getHttpStatusTitle(status),
2174
- status,
2175
- detail,
2176
- errors
2177
- };
2178
- response.status(status).send(problemDetails);
2179
2076
  }
2180
2077
  };
2181
- HttpExceptionFilter = _ts_decorate13([
2182
- (0, import_common18.Catch)()
2183
- ], HttpExceptionFilter);
2184
2078
 
2185
- // src/exceptions/base-field.exception.ts
2079
+ // src/exceptions/conflict.exception.ts
2186
2080
  var import_common19 = require("@nestjs/common");
2187
- var BaseFieldException = class extends import_common19.HttpException {
2081
+ var ConflictException = class extends BaseFieldException {
2188
2082
  static {
2189
- __name(this, "BaseFieldException");
2083
+ __name(this, "ConflictException");
2190
2084
  }
2191
- constructor(statusOrMessageOrErrors, messageOrStatus, statusOrDetail, detail) {
2192
- let errors;
2193
- let httpStatus;
2194
- let finalDetail;
2195
- if (Array.isArray(statusOrMessageOrErrors)) {
2196
- errors = statusOrMessageOrErrors;
2197
- httpStatus = messageOrStatus || import_common19.HttpStatus.BAD_REQUEST;
2198
- finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
2199
- } else if (typeof statusOrMessageOrErrors === "string" && typeof messageOrStatus === "string") {
2200
- errors = [
2201
- {
2202
- field: statusOrMessageOrErrors,
2203
- message: messageOrStatus
2204
- }
2205
- ];
2206
- httpStatus = statusOrDetail;
2207
- finalDetail = detail;
2208
- } else if (typeof statusOrMessageOrErrors === "string") {
2209
- errors = [
2210
- {
2211
- message: statusOrMessageOrErrors
2212
- }
2213
- ];
2214
- httpStatus = messageOrStatus;
2215
- finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
2085
+ constructor(messageOrField, fieldMessageOrDetail, detail) {
2086
+ if (Array.isArray(messageOrField)) {
2087
+ super(messageOrField, import_common19.HttpStatus.CONFLICT, fieldMessageOrDetail);
2088
+ } else if (detail !== void 0) {
2089
+ super(messageOrField, fieldMessageOrDetail, import_common19.HttpStatus.CONFLICT, detail);
2090
+ } else if (fieldMessageOrDetail) {
2091
+ super(messageOrField, fieldMessageOrDetail, import_common19.HttpStatus.CONFLICT);
2216
2092
  } else {
2217
- errors = [
2218
- {
2219
- message: "An error occurred"
2220
- }
2221
- ];
2222
- httpStatus = statusOrMessageOrErrors;
2223
- finalDetail = void 0;
2093
+ super(messageOrField, import_common19.HttpStatus.CONFLICT);
2224
2094
  }
2225
- const response = finalDetail !== void 0 ? {
2226
- errors,
2227
- detail: finalDetail
2228
- } : {
2229
- errors
2230
- };
2231
- super(response, httpStatus);
2232
2095
  }
2233
2096
  };
2234
2097
 
2235
- // src/exceptions/bad-request.exception.ts
2098
+ // src/exceptions/forbidden.exception.ts
2236
2099
  var import_common20 = require("@nestjs/common");
2237
- var BadRequestException = class extends BaseFieldException {
2100
+ var ForbiddenException = class extends BaseFieldException {
2238
2101
  static {
2239
- __name(this, "BadRequestException");
2102
+ __name(this, "ForbiddenException");
2240
2103
  }
2241
2104
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2242
2105
  if (Array.isArray(messageOrField)) {
2243
- super(messageOrField, import_common20.HttpStatus.BAD_REQUEST, fieldMessageOrDetail);
2106
+ super(messageOrField, import_common20.HttpStatus.FORBIDDEN, fieldMessageOrDetail);
2244
2107
  } else if (detail !== void 0) {
2245
- super(messageOrField, fieldMessageOrDetail, import_common20.HttpStatus.BAD_REQUEST, detail);
2108
+ super(messageOrField, fieldMessageOrDetail, import_common20.HttpStatus.FORBIDDEN, detail);
2246
2109
  } else if (fieldMessageOrDetail) {
2247
- super(messageOrField, fieldMessageOrDetail, import_common20.HttpStatus.BAD_REQUEST);
2110
+ super(messageOrField, fieldMessageOrDetail, import_common20.HttpStatus.FORBIDDEN);
2248
2111
  } else {
2249
- super(messageOrField, import_common20.HttpStatus.BAD_REQUEST);
2112
+ super(messageOrField, import_common20.HttpStatus.FORBIDDEN);
2250
2113
  }
2251
2114
  }
2252
2115
  };
2253
2116
 
2254
- // src/exceptions/unauthorized.exception.ts
2117
+ // src/exceptions/gone.exception.ts
2255
2118
  var import_common21 = require("@nestjs/common");
2256
- var UnauthorizedException4 = class extends BaseFieldException {
2119
+ var GoneException = class extends BaseFieldException {
2257
2120
  static {
2258
- __name(this, "UnauthorizedException");
2121
+ __name(this, "GoneException");
2259
2122
  }
2260
2123
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2261
2124
  if (Array.isArray(messageOrField)) {
2262
- super(messageOrField, import_common21.HttpStatus.UNAUTHORIZED, fieldMessageOrDetail);
2125
+ super(messageOrField, import_common21.HttpStatus.GONE, fieldMessageOrDetail);
2263
2126
  } else if (detail !== void 0) {
2264
- super(messageOrField, fieldMessageOrDetail, import_common21.HttpStatus.UNAUTHORIZED, detail);
2127
+ super(messageOrField, fieldMessageOrDetail, import_common21.HttpStatus.GONE, detail);
2265
2128
  } else if (fieldMessageOrDetail) {
2266
- super(messageOrField, fieldMessageOrDetail, import_common21.HttpStatus.UNAUTHORIZED);
2129
+ super(messageOrField, fieldMessageOrDetail, import_common21.HttpStatus.GONE);
2267
2130
  } else {
2268
- super(messageOrField, import_common21.HttpStatus.UNAUTHORIZED);
2131
+ super(messageOrField, import_common21.HttpStatus.GONE);
2269
2132
  }
2270
2133
  }
2271
2134
  };
2272
2135
 
2273
- // src/exceptions/forbidden.exception.ts
2136
+ // src/exceptions/internal-server-error.exception.ts
2274
2137
  var import_common22 = require("@nestjs/common");
2275
- var ForbiddenException2 = class extends BaseFieldException {
2138
+ var InternalServerErrorException3 = class extends BaseFieldException {
2276
2139
  static {
2277
- __name(this, "ForbiddenException");
2140
+ __name(this, "InternalServerErrorException");
2278
2141
  }
2279
2142
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2280
2143
  if (Array.isArray(messageOrField)) {
2281
- super(messageOrField, import_common22.HttpStatus.FORBIDDEN, fieldMessageOrDetail);
2144
+ super(messageOrField, import_common22.HttpStatus.INTERNAL_SERVER_ERROR, fieldMessageOrDetail);
2282
2145
  } else if (detail !== void 0) {
2283
- super(messageOrField, fieldMessageOrDetail, import_common22.HttpStatus.FORBIDDEN, detail);
2146
+ super(messageOrField, fieldMessageOrDetail, import_common22.HttpStatus.INTERNAL_SERVER_ERROR, detail);
2284
2147
  } else if (fieldMessageOrDetail) {
2285
- super(messageOrField, fieldMessageOrDetail, import_common22.HttpStatus.FORBIDDEN);
2148
+ super(messageOrField, fieldMessageOrDetail, import_common22.HttpStatus.INTERNAL_SERVER_ERROR);
2286
2149
  } else {
2287
- super(messageOrField, import_common22.HttpStatus.FORBIDDEN);
2150
+ super(messageOrField, import_common22.HttpStatus.INTERNAL_SERVER_ERROR);
2288
2151
  }
2289
2152
  }
2290
2153
  };
2291
2154
 
2292
- // src/exceptions/not-found.exception.ts
2155
+ // src/exceptions/method-not-allowed.exception.ts
2293
2156
  var import_common23 = require("@nestjs/common");
2294
- var NotFoundException = class extends BaseFieldException {
2157
+ var MethodNotAllowedException = class extends BaseFieldException {
2295
2158
  static {
2296
- __name(this, "NotFoundException");
2159
+ __name(this, "MethodNotAllowedException");
2297
2160
  }
2298
2161
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2299
2162
  if (Array.isArray(messageOrField)) {
2300
- super(messageOrField, import_common23.HttpStatus.NOT_FOUND, fieldMessageOrDetail);
2163
+ super(messageOrField, import_common23.HttpStatus.METHOD_NOT_ALLOWED, fieldMessageOrDetail);
2301
2164
  } else if (detail !== void 0) {
2302
- super(messageOrField, fieldMessageOrDetail, import_common23.HttpStatus.NOT_FOUND, detail);
2165
+ super(messageOrField, fieldMessageOrDetail, import_common23.HttpStatus.METHOD_NOT_ALLOWED, detail);
2303
2166
  } else if (fieldMessageOrDetail) {
2304
- super(messageOrField, fieldMessageOrDetail, import_common23.HttpStatus.NOT_FOUND);
2167
+ super(messageOrField, fieldMessageOrDetail, import_common23.HttpStatus.METHOD_NOT_ALLOWED);
2305
2168
  } else {
2306
- super(messageOrField, import_common23.HttpStatus.NOT_FOUND);
2169
+ super(messageOrField, import_common23.HttpStatus.METHOD_NOT_ALLOWED);
2307
2170
  }
2308
2171
  }
2309
2172
  };
2310
2173
 
2311
- // src/exceptions/conflict.exception.ts
2174
+ // src/exceptions/not-acceptable.exception.ts
2312
2175
  var import_common24 = require("@nestjs/common");
2313
- var ConflictException = class extends BaseFieldException {
2176
+ var NotAcceptableException = class extends BaseFieldException {
2314
2177
  static {
2315
- __name(this, "ConflictException");
2178
+ __name(this, "NotAcceptableException");
2316
2179
  }
2317
2180
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2318
2181
  if (Array.isArray(messageOrField)) {
2319
- super(messageOrField, import_common24.HttpStatus.CONFLICT, fieldMessageOrDetail);
2182
+ super(messageOrField, import_common24.HttpStatus.NOT_ACCEPTABLE, fieldMessageOrDetail);
2320
2183
  } else if (detail !== void 0) {
2321
- super(messageOrField, fieldMessageOrDetail, import_common24.HttpStatus.CONFLICT, detail);
2184
+ super(messageOrField, fieldMessageOrDetail, import_common24.HttpStatus.NOT_ACCEPTABLE, detail);
2322
2185
  } else if (fieldMessageOrDetail) {
2323
- super(messageOrField, fieldMessageOrDetail, import_common24.HttpStatus.CONFLICT);
2186
+ super(messageOrField, fieldMessageOrDetail, import_common24.HttpStatus.NOT_ACCEPTABLE);
2324
2187
  } else {
2325
- super(messageOrField, import_common24.HttpStatus.CONFLICT);
2188
+ super(messageOrField, import_common24.HttpStatus.NOT_ACCEPTABLE);
2326
2189
  }
2327
2190
  }
2328
2191
  };
2329
2192
 
2330
- // src/exceptions/internal-server-error.exception.ts
2193
+ // src/exceptions/not-found.exception.ts
2331
2194
  var import_common25 = require("@nestjs/common");
2332
- var InternalServerErrorException3 = class extends BaseFieldException {
2195
+ var NotFoundException = class extends BaseFieldException {
2333
2196
  static {
2334
- __name(this, "InternalServerErrorException");
2197
+ __name(this, "NotFoundException");
2335
2198
  }
2336
2199
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2337
2200
  if (Array.isArray(messageOrField)) {
2338
- super(messageOrField, import_common25.HttpStatus.INTERNAL_SERVER_ERROR, fieldMessageOrDetail);
2201
+ super(messageOrField, import_common25.HttpStatus.NOT_FOUND, fieldMessageOrDetail);
2339
2202
  } else if (detail !== void 0) {
2340
- super(messageOrField, fieldMessageOrDetail, import_common25.HttpStatus.INTERNAL_SERVER_ERROR, detail);
2203
+ super(messageOrField, fieldMessageOrDetail, import_common25.HttpStatus.NOT_FOUND, detail);
2341
2204
  } else if (fieldMessageOrDetail) {
2342
- super(messageOrField, fieldMessageOrDetail, import_common25.HttpStatus.INTERNAL_SERVER_ERROR);
2205
+ super(messageOrField, fieldMessageOrDetail, import_common25.HttpStatus.NOT_FOUND);
2343
2206
  } else {
2344
- super(messageOrField, import_common25.HttpStatus.INTERNAL_SERVER_ERROR);
2207
+ super(messageOrField, import_common25.HttpStatus.NOT_FOUND);
2345
2208
  }
2346
2209
  }
2347
2210
  };
2348
2211
 
2349
- // src/exceptions/validation.exception.ts
2212
+ // src/exceptions/not-implemented.exception.ts
2350
2213
  var import_common26 = require("@nestjs/common");
2351
- var ValidationException = class extends BaseFieldException {
2214
+ var NotImplementedException = class extends BaseFieldException {
2352
2215
  static {
2353
- __name(this, "ValidationException");
2216
+ __name(this, "NotImplementedException");
2354
2217
  }
2355
- constructor(errors, detail) {
2356
- super(errors, import_common26.HttpStatus.BAD_REQUEST, detail);
2218
+ constructor(messageOrField, fieldMessageOrDetail, detail) {
2219
+ if (Array.isArray(messageOrField)) {
2220
+ super(messageOrField, import_common26.HttpStatus.NOT_IMPLEMENTED, fieldMessageOrDetail);
2221
+ } else if (detail !== void 0) {
2222
+ super(messageOrField, fieldMessageOrDetail, import_common26.HttpStatus.NOT_IMPLEMENTED, detail);
2223
+ } else if (fieldMessageOrDetail) {
2224
+ super(messageOrField, fieldMessageOrDetail, import_common26.HttpStatus.NOT_IMPLEMENTED);
2225
+ } else {
2226
+ super(messageOrField, import_common26.HttpStatus.NOT_IMPLEMENTED);
2227
+ }
2357
2228
  }
2358
2229
  };
2359
2230
 
2360
- // src/exceptions/unprocessable-entity.exception.ts
2231
+ // src/exceptions/payload-too-large.exception.ts
2361
2232
  var import_common27 = require("@nestjs/common");
2362
- var UnprocessableEntityException = class extends BaseFieldException {
2233
+ var PayloadTooLargeException = class extends BaseFieldException {
2363
2234
  static {
2364
- __name(this, "UnprocessableEntityException");
2235
+ __name(this, "PayloadTooLargeException");
2365
2236
  }
2366
2237
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2367
2238
  if (Array.isArray(messageOrField)) {
2368
- super(messageOrField, import_common27.HttpStatus.UNPROCESSABLE_ENTITY, fieldMessageOrDetail);
2239
+ super(messageOrField, import_common27.HttpStatus.PAYLOAD_TOO_LARGE, fieldMessageOrDetail);
2369
2240
  } else if (detail !== void 0) {
2370
- super(messageOrField, fieldMessageOrDetail, import_common27.HttpStatus.UNPROCESSABLE_ENTITY, detail);
2241
+ super(messageOrField, fieldMessageOrDetail, import_common27.HttpStatus.PAYLOAD_TOO_LARGE, detail);
2371
2242
  } else if (fieldMessageOrDetail) {
2372
- super(messageOrField, fieldMessageOrDetail, import_common27.HttpStatus.UNPROCESSABLE_ENTITY);
2243
+ super(messageOrField, fieldMessageOrDetail, import_common27.HttpStatus.PAYLOAD_TOO_LARGE);
2373
2244
  } else {
2374
- super(messageOrField, import_common27.HttpStatus.UNPROCESSABLE_ENTITY);
2245
+ super(messageOrField, import_common27.HttpStatus.PAYLOAD_TOO_LARGE);
2375
2246
  }
2376
2247
  }
2377
2248
  };
2378
2249
 
2379
- // src/exceptions/too-many-requests.exception.ts
2250
+ // src/exceptions/request-timeout.exception.ts
2380
2251
  var import_common28 = require("@nestjs/common");
2381
- var TooManyRequestsException = class extends BaseFieldException {
2252
+ var RequestTimeoutException = class extends BaseFieldException {
2382
2253
  static {
2383
- __name(this, "TooManyRequestsException");
2254
+ __name(this, "RequestTimeoutException");
2384
2255
  }
2385
2256
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2386
2257
  if (Array.isArray(messageOrField)) {
2387
- super(messageOrField, import_common28.HttpStatus.TOO_MANY_REQUESTS, fieldMessageOrDetail);
2258
+ super(messageOrField, import_common28.HttpStatus.REQUEST_TIMEOUT, fieldMessageOrDetail);
2388
2259
  } else if (detail !== void 0) {
2389
- super(messageOrField, fieldMessageOrDetail, import_common28.HttpStatus.TOO_MANY_REQUESTS, detail);
2260
+ super(messageOrField, fieldMessageOrDetail, import_common28.HttpStatus.REQUEST_TIMEOUT, detail);
2390
2261
  } else if (fieldMessageOrDetail) {
2391
- super(messageOrField, fieldMessageOrDetail, import_common28.HttpStatus.TOO_MANY_REQUESTS);
2262
+ super(messageOrField, fieldMessageOrDetail, import_common28.HttpStatus.REQUEST_TIMEOUT);
2392
2263
  } else {
2393
- super(messageOrField, import_common28.HttpStatus.TOO_MANY_REQUESTS);
2264
+ super(messageOrField, import_common28.HttpStatus.REQUEST_TIMEOUT);
2394
2265
  }
2395
2266
  }
2396
2267
  };
@@ -2414,217 +2285,521 @@ var ServiceUnavailableException = class extends BaseFieldException {
2414
2285
  }
2415
2286
  };
2416
2287
 
2417
- // src/exceptions/method-not-allowed.exception.ts
2288
+ // src/exceptions/too-many-requests.exception.ts
2418
2289
  var import_common30 = require("@nestjs/common");
2419
- var MethodNotAllowedException = class extends BaseFieldException {
2290
+ var TooManyRequestsException = class extends BaseFieldException {
2420
2291
  static {
2421
- __name(this, "MethodNotAllowedException");
2292
+ __name(this, "TooManyRequestsException");
2422
2293
  }
2423
2294
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2424
2295
  if (Array.isArray(messageOrField)) {
2425
- super(messageOrField, import_common30.HttpStatus.METHOD_NOT_ALLOWED, fieldMessageOrDetail);
2296
+ super(messageOrField, import_common30.HttpStatus.TOO_MANY_REQUESTS, fieldMessageOrDetail);
2426
2297
  } else if (detail !== void 0) {
2427
- super(messageOrField, fieldMessageOrDetail, import_common30.HttpStatus.METHOD_NOT_ALLOWED, detail);
2298
+ super(messageOrField, fieldMessageOrDetail, import_common30.HttpStatus.TOO_MANY_REQUESTS, detail);
2428
2299
  } else if (fieldMessageOrDetail) {
2429
- super(messageOrField, fieldMessageOrDetail, import_common30.HttpStatus.METHOD_NOT_ALLOWED);
2300
+ super(messageOrField, fieldMessageOrDetail, import_common30.HttpStatus.TOO_MANY_REQUESTS);
2430
2301
  } else {
2431
- super(messageOrField, import_common30.HttpStatus.METHOD_NOT_ALLOWED);
2302
+ super(messageOrField, import_common30.HttpStatus.TOO_MANY_REQUESTS);
2432
2303
  }
2433
2304
  }
2434
2305
  };
2435
2306
 
2436
- // src/exceptions/gone.exception.ts
2307
+ // src/exceptions/unauthorized.exception.ts
2437
2308
  var import_common31 = require("@nestjs/common");
2438
- var GoneException = class extends BaseFieldException {
2309
+ var UnauthorizedException4 = class extends BaseFieldException {
2439
2310
  static {
2440
- __name(this, "GoneException");
2311
+ __name(this, "UnauthorizedException");
2441
2312
  }
2442
2313
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2443
2314
  if (Array.isArray(messageOrField)) {
2444
- super(messageOrField, import_common31.HttpStatus.GONE, fieldMessageOrDetail);
2315
+ super(messageOrField, import_common31.HttpStatus.UNAUTHORIZED, fieldMessageOrDetail);
2445
2316
  } else if (detail !== void 0) {
2446
- super(messageOrField, fieldMessageOrDetail, import_common31.HttpStatus.GONE, detail);
2317
+ super(messageOrField, fieldMessageOrDetail, import_common31.HttpStatus.UNAUTHORIZED, detail);
2447
2318
  } else if (fieldMessageOrDetail) {
2448
- super(messageOrField, fieldMessageOrDetail, import_common31.HttpStatus.GONE);
2319
+ super(messageOrField, fieldMessageOrDetail, import_common31.HttpStatus.UNAUTHORIZED);
2449
2320
  } else {
2450
- super(messageOrField, import_common31.HttpStatus.GONE);
2321
+ super(messageOrField, import_common31.HttpStatus.UNAUTHORIZED);
2451
2322
  }
2452
2323
  }
2453
2324
  };
2454
2325
 
2455
- // src/exceptions/not-acceptable.exception.ts
2326
+ // src/exceptions/unprocessable-entity.exception.ts
2456
2327
  var import_common32 = require("@nestjs/common");
2457
- var NotAcceptableException = class extends BaseFieldException {
2328
+ var UnprocessableEntityException = class extends BaseFieldException {
2458
2329
  static {
2459
- __name(this, "NotAcceptableException");
2330
+ __name(this, "UnprocessableEntityException");
2460
2331
  }
2461
2332
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2462
2333
  if (Array.isArray(messageOrField)) {
2463
- super(messageOrField, import_common32.HttpStatus.NOT_ACCEPTABLE, fieldMessageOrDetail);
2334
+ super(messageOrField, import_common32.HttpStatus.UNPROCESSABLE_ENTITY, fieldMessageOrDetail);
2464
2335
  } else if (detail !== void 0) {
2465
- super(messageOrField, fieldMessageOrDetail, import_common32.HttpStatus.NOT_ACCEPTABLE, detail);
2336
+ super(messageOrField, fieldMessageOrDetail, import_common32.HttpStatus.UNPROCESSABLE_ENTITY, detail);
2466
2337
  } else if (fieldMessageOrDetail) {
2467
- super(messageOrField, fieldMessageOrDetail, import_common32.HttpStatus.NOT_ACCEPTABLE);
2338
+ super(messageOrField, fieldMessageOrDetail, import_common32.HttpStatus.UNPROCESSABLE_ENTITY);
2468
2339
  } else {
2469
- super(messageOrField, import_common32.HttpStatus.NOT_ACCEPTABLE);
2340
+ super(messageOrField, import_common32.HttpStatus.UNPROCESSABLE_ENTITY);
2470
2341
  }
2471
2342
  }
2472
2343
  };
2473
2344
 
2474
- // src/exceptions/request-timeout.exception.ts
2345
+ // src/exceptions/unsupported-media-type.exception.ts
2475
2346
  var import_common33 = require("@nestjs/common");
2476
- var RequestTimeoutException = class extends BaseFieldException {
2347
+ var UnsupportedMediaTypeException = class extends BaseFieldException {
2477
2348
  static {
2478
- __name(this, "RequestTimeoutException");
2349
+ __name(this, "UnsupportedMediaTypeException");
2479
2350
  }
2480
2351
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2481
2352
  if (Array.isArray(messageOrField)) {
2482
- super(messageOrField, import_common33.HttpStatus.REQUEST_TIMEOUT, fieldMessageOrDetail);
2353
+ super(messageOrField, import_common33.HttpStatus.UNSUPPORTED_MEDIA_TYPE, fieldMessageOrDetail);
2483
2354
  } else if (detail !== void 0) {
2484
- super(messageOrField, fieldMessageOrDetail, import_common33.HttpStatus.REQUEST_TIMEOUT, detail);
2355
+ super(messageOrField, fieldMessageOrDetail, import_common33.HttpStatus.UNSUPPORTED_MEDIA_TYPE, detail);
2485
2356
  } else if (fieldMessageOrDetail) {
2486
- super(messageOrField, fieldMessageOrDetail, import_common33.HttpStatus.REQUEST_TIMEOUT);
2357
+ super(messageOrField, fieldMessageOrDetail, import_common33.HttpStatus.UNSUPPORTED_MEDIA_TYPE);
2487
2358
  } else {
2488
- super(messageOrField, import_common33.HttpStatus.REQUEST_TIMEOUT);
2359
+ super(messageOrField, import_common33.HttpStatus.UNSUPPORTED_MEDIA_TYPE);
2489
2360
  }
2490
2361
  }
2491
2362
  };
2492
2363
 
2493
- // src/exceptions/payload-too-large.exception.ts
2364
+ // src/exceptions/validation.exception.ts
2494
2365
  var import_common34 = require("@nestjs/common");
2495
- var PayloadTooLargeException = class extends BaseFieldException {
2366
+ var ValidationException = class extends BaseFieldException {
2496
2367
  static {
2497
- __name(this, "PayloadTooLargeException");
2368
+ __name(this, "ValidationException");
2498
2369
  }
2499
- constructor(messageOrField, fieldMessageOrDetail, detail) {
2500
- if (Array.isArray(messageOrField)) {
2501
- super(messageOrField, import_common34.HttpStatus.PAYLOAD_TOO_LARGE, fieldMessageOrDetail);
2502
- } else if (detail !== void 0) {
2503
- super(messageOrField, fieldMessageOrDetail, import_common34.HttpStatus.PAYLOAD_TOO_LARGE, detail);
2504
- } else if (fieldMessageOrDetail) {
2505
- super(messageOrField, fieldMessageOrDetail, import_common34.HttpStatus.PAYLOAD_TOO_LARGE);
2506
- } else {
2507
- super(messageOrField, import_common34.HttpStatus.PAYLOAD_TOO_LARGE);
2508
- }
2370
+ constructor(errors, detail) {
2371
+ super(errors, import_common34.HttpStatus.BAD_REQUEST, detail);
2509
2372
  }
2510
2373
  };
2511
2374
 
2512
- // src/exceptions/unsupported-media-type.exception.ts
2375
+ // src/filters/http-exception.filter.ts
2513
2376
  var import_common35 = require("@nestjs/common");
2514
- var UnsupportedMediaTypeException = class extends BaseFieldException {
2377
+ function _ts_decorate11(decorators, target, key, desc) {
2378
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2379
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2380
+ 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;
2381
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2382
+ }
2383
+ __name(_ts_decorate11, "_ts_decorate");
2384
+ function getHttpStatusTitle(status) {
2385
+ const enumKey = Object.entries(import_common35.HttpStatus).find(([key, value]) => value === status && Number.isNaN(Number(key)))?.[0];
2386
+ if (!enumKey) {
2387
+ return "Error";
2388
+ }
2389
+ return enumKey.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
2390
+ }
2391
+ __name(getHttpStatusTitle, "getHttpStatusTitle");
2392
+ var HttpExceptionFilter = class _HttpExceptionFilter {
2515
2393
  static {
2516
- __name(this, "UnsupportedMediaTypeException");
2394
+ __name(this, "HttpExceptionFilter");
2517
2395
  }
2518
- constructor(messageOrField, fieldMessageOrDetail, detail) {
2519
- if (Array.isArray(messageOrField)) {
2520
- super(messageOrField, import_common35.HttpStatus.UNSUPPORTED_MEDIA_TYPE, fieldMessageOrDetail);
2521
- } else if (detail !== void 0) {
2522
- super(messageOrField, fieldMessageOrDetail, import_common35.HttpStatus.UNSUPPORTED_MEDIA_TYPE, detail);
2523
- } else if (fieldMessageOrDetail) {
2524
- super(messageOrField, fieldMessageOrDetail, import_common35.HttpStatus.UNSUPPORTED_MEDIA_TYPE);
2396
+ logger = new import_common35.Logger(_HttpExceptionFilter.name);
2397
+ catch(exception, host) {
2398
+ const ctx = host.switchToHttp();
2399
+ const response = ctx.getResponse();
2400
+ let status = import_common35.HttpStatus.INTERNAL_SERVER_ERROR;
2401
+ let errors = [];
2402
+ let detail = "Internal server error";
2403
+ if (exception instanceof import_common35.HttpException) {
2404
+ status = exception.getStatus();
2405
+ const exceptionResponse = exception.getResponse();
2406
+ if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
2407
+ const responseObj = exceptionResponse;
2408
+ if ("errors" in responseObj && Array.isArray(responseObj.errors)) {
2409
+ errors = responseObj.errors;
2410
+ detail = ("detail" in responseObj ? responseObj.detail : void 0) || exception.message;
2411
+ } else if ("message" in responseObj && Array.isArray(responseObj.message)) {
2412
+ errors = responseObj.message.map((msg) => {
2413
+ if (typeof msg === "object" && "property" in msg && "constraints" in msg) {
2414
+ const constraintValues = Object.values(msg.constraints);
2415
+ return {
2416
+ field: msg.property,
2417
+ message: constraintValues[0] ?? "Validation failed"
2418
+ };
2419
+ }
2420
+ return {
2421
+ message: typeof msg === "string" ? msg : JSON.stringify(msg)
2422
+ };
2423
+ });
2424
+ detail = "Validation failed";
2425
+ } else if ("message" in responseObj) {
2426
+ const message = responseObj.message;
2427
+ errors = [
2428
+ {
2429
+ message: Array.isArray(message) ? message.join(", ") : message
2430
+ }
2431
+ ];
2432
+ detail = ("error" in responseObj ? responseObj.error : void 0) || exception.message;
2433
+ }
2434
+ } else if (typeof exceptionResponse === "string") {
2435
+ errors = [
2436
+ {
2437
+ message: exceptionResponse
2438
+ }
2439
+ ];
2440
+ detail = exceptionResponse;
2441
+ }
2525
2442
  } else {
2526
- super(messageOrField, import_common35.HttpStatus.UNSUPPORTED_MEDIA_TYPE);
2443
+ const errorMessage = exception instanceof Error ? exception.message : "Unknown error";
2444
+ const stack = exception instanceof Error ? exception.stack : void 0;
2445
+ this.logger.error(`Unexpected error: ${errorMessage}`, stack);
2446
+ errors = [
2447
+ {
2448
+ message: "An unexpected error occurred"
2449
+ }
2450
+ ];
2527
2451
  }
2452
+ const problemDetails = {
2453
+ title: getHttpStatusTitle(status),
2454
+ status,
2455
+ detail,
2456
+ errors
2457
+ };
2458
+ response.status(status).send(problemDetails);
2528
2459
  }
2529
2460
  };
2461
+ HttpExceptionFilter = _ts_decorate11([
2462
+ (0, import_common35.Catch)()
2463
+ ], HttpExceptionFilter);
2530
2464
 
2531
- // src/exceptions/not-implemented.exception.ts
2465
+ // src/http/guards/csrf.guard.ts
2532
2466
  var import_common36 = require("@nestjs/common");
2533
- var NotImplementedException = class extends BaseFieldException {
2467
+ function _ts_decorate12(decorators, target, key, desc) {
2468
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2469
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2470
+ 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;
2471
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2472
+ }
2473
+ __name(_ts_decorate12, "_ts_decorate");
2474
+ var CsrfGuard = class _CsrfGuard {
2534
2475
  static {
2535
- __name(this, "NotImplementedException");
2476
+ __name(this, "CsrfGuard");
2536
2477
  }
2537
- constructor(messageOrField, fieldMessageOrDetail, detail) {
2538
- if (Array.isArray(messageOrField)) {
2539
- super(messageOrField, import_common36.HttpStatus.NOT_IMPLEMENTED, fieldMessageOrDetail);
2540
- } else if (detail !== void 0) {
2541
- super(messageOrField, fieldMessageOrDetail, import_common36.HttpStatus.NOT_IMPLEMENTED, detail);
2542
- } else if (fieldMessageOrDetail) {
2543
- super(messageOrField, fieldMessageOrDetail, import_common36.HttpStatus.NOT_IMPLEMENTED);
2544
- } else {
2545
- super(messageOrField, import_common36.HttpStatus.NOT_IMPLEMENTED);
2478
+ logger = new import_common36.Logger(_CsrfGuard.name);
2479
+ async canActivate(context) {
2480
+ const request = context.switchToHttp().getRequest();
2481
+ const reply = context.switchToHttp().getResponse();
2482
+ const safeMethods = [
2483
+ "GET",
2484
+ "HEAD",
2485
+ "OPTIONS"
2486
+ ];
2487
+ if (safeMethods.includes(request.method)) {
2488
+ return true;
2489
+ }
2490
+ try {
2491
+ const fastifyInstance = request.server;
2492
+ if (!fastifyInstance.csrfProtection) {
2493
+ this.logger.error("CSRF protection plugin not found. Ensure @fastify/csrf-protection is registered.");
2494
+ throw new import_common36.ForbiddenException("CSRF protection not configured");
2495
+ }
2496
+ await new Promise((resolve, reject) => {
2497
+ fastifyInstance.csrfProtection(request, reply, (err) => {
2498
+ if (err) {
2499
+ reject(err);
2500
+ } else {
2501
+ resolve();
2502
+ }
2503
+ });
2504
+ });
2505
+ this.logger.debug(`CSRF validation successful for ${request.method} ${request.url}`);
2506
+ return true;
2507
+ } catch (error) {
2508
+ this.logger.warn(`CSRF validation failed for ${request.method} ${request.url}: ${error instanceof Error ? error.message : "Unknown error"}`);
2509
+ throw new import_common36.ForbiddenException({
2510
+ errors: [
2511
+ {
2512
+ field: "csrf",
2513
+ message: "Invalid or missing CSRF token"
2514
+ }
2515
+ ],
2516
+ message: "CSRF validation failed"
2517
+ });
2546
2518
  }
2547
2519
  }
2548
2520
  };
2521
+ CsrfGuard = _ts_decorate12([
2522
+ (0, import_common36.Injectable)()
2523
+ ], CsrfGuard);
2549
2524
 
2550
- // src/exceptions/bad-gateway.exception.ts
2525
+ // src/http/http.module.ts
2551
2526
  var import_common37 = require("@nestjs/common");
2552
- var BadGatewayException = class extends BaseFieldException {
2527
+ function _ts_decorate13(decorators, target, key, desc) {
2528
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2529
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2530
+ 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;
2531
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2532
+ }
2533
+ __name(_ts_decorate13, "_ts_decorate");
2534
+ var HttpModule = class {
2553
2535
  static {
2554
- __name(this, "BadGatewayException");
2536
+ __name(this, "HttpModule");
2555
2537
  }
2556
- constructor(messageOrField, fieldMessageOrDetail, detail) {
2557
- if (Array.isArray(messageOrField)) {
2558
- super(messageOrField, import_common37.HttpStatus.BAD_GATEWAY, fieldMessageOrDetail);
2559
- } else if (detail !== void 0) {
2560
- super(messageOrField, fieldMessageOrDetail, import_common37.HttpStatus.BAD_GATEWAY, detail);
2561
- } else if (fieldMessageOrDetail) {
2562
- super(messageOrField, fieldMessageOrDetail, import_common37.HttpStatus.BAD_GATEWAY);
2563
- } else {
2564
- super(messageOrField, import_common37.HttpStatus.BAD_GATEWAY);
2538
+ };
2539
+ HttpModule = _ts_decorate13([
2540
+ (0, import_common37.Module)({
2541
+ providers: [
2542
+ CsrfGuard
2543
+ ],
2544
+ exports: [
2545
+ CsrfGuard
2546
+ ]
2547
+ })
2548
+ ], HttpModule);
2549
+
2550
+ // src/logger/interceptors/http-logger.interceptor.ts
2551
+ var import_common38 = require("@nestjs/common");
2552
+ var import_operators2 = require("rxjs/operators");
2553
+
2554
+ // src/logger/utils/index.ts
2555
+ var import_node_async_hooks = require("async_hooks");
2556
+ var import_node_crypto = require("crypto");
2557
+ var correlationStorage = new import_node_async_hooks.AsyncLocalStorage();
2558
+ function getCorrelationContext() {
2559
+ return correlationStorage.getStore();
2560
+ }
2561
+ __name(getCorrelationContext, "getCorrelationContext");
2562
+ function runWithCorrelationContext(context, callback) {
2563
+ return correlationStorage.run(context, callback);
2564
+ }
2565
+ __name(runWithCorrelationContext, "runWithCorrelationContext");
2566
+ function updateCorrelationContext(updates) {
2567
+ const context = correlationStorage.getStore();
2568
+ if (context) {
2569
+ Object.assign(context, updates);
2570
+ }
2571
+ }
2572
+ __name(updateCorrelationContext, "updateCorrelationContext");
2573
+ var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
2574
+ function generateCorrelationId() {
2575
+ return (0, import_node_crypto.randomUUID)();
2576
+ }
2577
+ __name(generateCorrelationId, "generateCorrelationId");
2578
+ function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
2579
+ if (typeof reply.header === "function") {
2580
+ reply.header(headerName, correlationId);
2581
+ } else if (reply.raw && typeof reply.raw.setHeader === "function") {
2582
+ reply.raw.setHeader(headerName, correlationId);
2583
+ }
2584
+ }
2585
+ __name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
2586
+
2587
+ // src/logger/interceptors/http-logger.interceptor.ts
2588
+ function _ts_decorate14(decorators, target, key, desc) {
2589
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2590
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2591
+ 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;
2592
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2593
+ }
2594
+ __name(_ts_decorate14, "_ts_decorate");
2595
+ function _ts_metadata7(k, v) {
2596
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2597
+ }
2598
+ __name(_ts_metadata7, "_ts_metadata");
2599
+ function _ts_param4(paramIndex, decorator) {
2600
+ return function(target, key) {
2601
+ decorator(target, key, paramIndex);
2602
+ };
2603
+ }
2604
+ __name(_ts_param4, "_ts_param");
2605
+ var HttpLoggerInterceptor = class {
2606
+ static {
2607
+ __name(this, "HttpLoggerInterceptor");
2608
+ }
2609
+ logger;
2610
+ enableRequestLog;
2611
+ enableResponseLog;
2612
+ slowRequestThreshold;
2613
+ constructor(logger, options) {
2614
+ this.logger = logger;
2615
+ this.enableRequestLog = options?.enableRequestLog ?? true;
2616
+ this.enableResponseLog = options?.enableResponseLog ?? true;
2617
+ this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
2618
+ }
2619
+ intercept(context, next) {
2620
+ if (context.getType() !== "http") {
2621
+ return next.handle();
2622
+ }
2623
+ const httpContext = context.switchToHttp();
2624
+ const request = httpContext.getRequest();
2625
+ const response = httpContext.getResponse();
2626
+ const startTime = Date.now();
2627
+ if (this.enableRequestLog) {
2628
+ this.logRequest(request);
2629
+ }
2630
+ return next.handle().pipe((0, import_operators2.tap)(() => {
2631
+ if (this.enableResponseLog) {
2632
+ const duration = Date.now() - startTime;
2633
+ this.logResponse(request, response, duration);
2634
+ }
2635
+ }), (0, import_operators2.catchError)((error) => {
2636
+ const duration = Date.now() - startTime;
2637
+ this.logError(request, response, duration, error);
2638
+ throw error;
2639
+ }));
2640
+ }
2641
+ logRequest(request) {
2642
+ try {
2643
+ const correlationContext = getCorrelationContext();
2644
+ const metadata = {
2645
+ type: "http_request",
2646
+ method: request.method,
2647
+ url: request.url,
2648
+ correlationId: correlationContext?.correlationId,
2649
+ ip: request.ip,
2650
+ userAgent: request.headers["user-agent"]
2651
+ };
2652
+ this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
2653
+ } catch (error) {
2654
+ this.logger.error("Failed to log HTTP request", error.stack);
2655
+ }
2656
+ }
2657
+ logResponse(request, response, duration) {
2658
+ try {
2659
+ const correlationContext = getCorrelationContext();
2660
+ const statusCode = response.statusCode;
2661
+ const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
2662
+ const metadata = {
2663
+ type: "http_response",
2664
+ method: request.method,
2665
+ url: request.url,
2666
+ statusCode,
2667
+ duration,
2668
+ correlationId: correlationContext?.correlationId
2669
+ };
2670
+ if (duration > this.slowRequestThreshold) {
2671
+ metadata.slowRequest = true;
2672
+ }
2673
+ const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
2674
+ this.logger.logWithMetadata(logLevel, message, metadata);
2675
+ } catch (error) {
2676
+ this.logger.error("Failed to log HTTP response", error.stack);
2677
+ }
2678
+ }
2679
+ logError(request, response, duration, error) {
2680
+ try {
2681
+ const correlationContext = getCorrelationContext();
2682
+ const statusCode = response.statusCode || 500;
2683
+ const metadata = {
2684
+ type: "http_error",
2685
+ method: request.method,
2686
+ url: request.url,
2687
+ statusCode,
2688
+ duration,
2689
+ correlationId: correlationContext?.correlationId,
2690
+ errorName: error?.name || "Error",
2691
+ errorMessage: error?.message || "Unknown error"
2692
+ };
2693
+ if (error?.stack) {
2694
+ metadata.trace = error.stack;
2695
+ }
2696
+ if (error?.response) {
2697
+ metadata.errorDetails = error.response;
2698
+ }
2699
+ const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
2700
+ this.logger.logWithMetadata("error", message, metadata);
2701
+ } catch (loggingError) {
2702
+ this.logger.error("Failed to log HTTP error", loggingError.stack);
2703
+ }
2704
+ }
2705
+ };
2706
+ HttpLoggerInterceptor = _ts_decorate14([
2707
+ (0, import_common38.Injectable)(),
2708
+ _ts_param4(1, (0, import_common38.Optional)()),
2709
+ _ts_metadata7("design:type", Function),
2710
+ _ts_metadata7("design:paramtypes", [
2711
+ typeof LoggerService === "undefined" ? Object : LoggerService,
2712
+ typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
2713
+ ])
2714
+ ], HttpLoggerInterceptor);
2715
+
2716
+ // src/logger/logger.module.ts
2717
+ var import_common41 = require("@nestjs/common");
2718
+
2719
+ // src/logger/middleware/correlation-id.middleware.ts
2720
+ var import_common39 = require("@nestjs/common");
2721
+ function _ts_decorate15(decorators, target, key, desc) {
2722
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2723
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2724
+ 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;
2725
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2726
+ }
2727
+ __name(_ts_decorate15, "_ts_decorate");
2728
+ function _ts_metadata8(k, v) {
2729
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2730
+ }
2731
+ __name(_ts_metadata8, "_ts_metadata");
2732
+ var CorrelationIdMiddleware = class {
2733
+ static {
2734
+ __name(this, "CorrelationIdMiddleware");
2735
+ }
2736
+ includeInResponse;
2737
+ responseHeader;
2738
+ constructor(options = {}) {
2739
+ this.includeInResponse = options.includeInResponse ?? true;
2740
+ this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
2741
+ }
2742
+ /**
2743
+ * Middleware handler for processing requests.
2744
+ */
2745
+ use(_req, reply, next) {
2746
+ const correlationId = generateCorrelationId();
2747
+ if (this.includeInResponse) {
2748
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2749
+ }
2750
+ runWithCorrelationContext({
2751
+ correlationId
2752
+ }, () => {
2753
+ next();
2754
+ });
2755
+ }
2756
+ /**
2757
+ * Fastify hook handler for onRequest.
2758
+ * This is an async function that returns a Promise, ensuring the AsyncLocalStorage
2759
+ * context persists throughout the entire request lifecycle.
2760
+ */
2761
+ async onRequest(_req, reply) {
2762
+ const correlationId = generateCorrelationId();
2763
+ if (this.includeInResponse) {
2764
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2765
+ }
2766
+ const store = correlationStorage.getStore();
2767
+ if (!store) {
2768
+ correlationStorage.enterWith({
2769
+ correlationId
2770
+ });
2565
2771
  }
2566
2772
  }
2567
2773
  };
2568
-
2569
- // src/logger/logger.module.ts
2570
- var import_common41 = require("@nestjs/common");
2774
+ CorrelationIdMiddleware = _ts_decorate15([
2775
+ (0, import_common39.Injectable)(),
2776
+ _ts_metadata8("design:type", Function),
2777
+ _ts_metadata8("design:paramtypes", [
2778
+ typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
2779
+ ])
2780
+ ], CorrelationIdMiddleware);
2571
2781
 
2572
2782
  // src/logger/services/logger.service.ts
2573
- var import_common38 = require("@nestjs/common");
2783
+ var import_common40 = require("@nestjs/common");
2574
2784
  var import_winston = require("winston");
2575
2785
  var import_winston_daily_rotate_file = __toESM(require("winston-daily-rotate-file"), 1);
2576
-
2577
- // src/logger/utils/index.ts
2578
- var import_node_async_hooks = require("async_hooks");
2579
- var import_node_crypto = require("crypto");
2580
- var correlationStorage = new import_node_async_hooks.AsyncLocalStorage();
2581
- function getCorrelationContext() {
2582
- return correlationStorage.getStore();
2583
- }
2584
- __name(getCorrelationContext, "getCorrelationContext");
2585
- function runWithCorrelationContext(context, callback) {
2586
- return correlationStorage.run(context, callback);
2587
- }
2588
- __name(runWithCorrelationContext, "runWithCorrelationContext");
2589
- function updateCorrelationContext(updates) {
2590
- const context = correlationStorage.getStore();
2591
- if (context) {
2592
- Object.assign(context, updates);
2593
- }
2594
- }
2595
- __name(updateCorrelationContext, "updateCorrelationContext");
2596
- var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
2597
- function generateCorrelationId() {
2598
- return (0, import_node_crypto.randomUUID)();
2599
- }
2600
- __name(generateCorrelationId, "generateCorrelationId");
2601
- function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
2602
- if (typeof reply.header === "function") {
2603
- reply.header(headerName, correlationId);
2604
- } else if (reply.raw && typeof reply.raw.setHeader === "function") {
2605
- reply.raw.setHeader(headerName, correlationId);
2606
- }
2607
- }
2608
- __name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
2609
-
2610
- // src/logger/services/logger.service.ts
2611
- function _ts_decorate14(decorators, target, key, desc) {
2786
+ function _ts_decorate16(decorators, target, key, desc) {
2612
2787
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2613
2788
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2614
2789
  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;
2615
2790
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2616
2791
  }
2617
- __name(_ts_decorate14, "_ts_decorate");
2618
- function _ts_metadata8(k, v) {
2792
+ __name(_ts_decorate16, "_ts_decorate");
2793
+ function _ts_metadata9(k, v) {
2619
2794
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2620
2795
  }
2621
- __name(_ts_metadata8, "_ts_metadata");
2622
- function _ts_param4(paramIndex, decorator) {
2796
+ __name(_ts_metadata9, "_ts_metadata");
2797
+ function _ts_param5(paramIndex, decorator) {
2623
2798
  return function(target, key) {
2624
2799
  decorator(target, key, paramIndex);
2625
2800
  };
2626
2801
  }
2627
- __name(_ts_param4, "_ts_param");
2802
+ __name(_ts_param5, "_ts_param");
2628
2803
  var LoggerService2 = class _LoggerService {
2629
2804
  static {
2630
2805
  __name(this, "LoggerService");
@@ -2677,7 +2852,8 @@ var LoggerService2 = class _LoggerService {
2677
2852
  ].filter(Boolean);
2678
2853
  let output = parts.join(" ");
2679
2854
  if (trace) {
2680
- output += "\n" + trace;
2855
+ output += `
2856
+ ${trace}`;
2681
2857
  }
2682
2858
  return output;
2683
2859
  }), import_winston.format.colorize({
@@ -2825,210 +3001,16 @@ var LoggerService2 = class _LoggerService {
2825
3001
  return childLogger;
2826
3002
  }
2827
3003
  };
2828
- LoggerService2 = _ts_decorate14([
2829
- (0, import_common38.Injectable)(),
2830
- _ts_param4(0, (0, import_common38.Optional)()),
2831
- _ts_param4(1, (0, import_common38.Optional)()),
2832
- _ts_metadata8("design:type", Function),
2833
- _ts_metadata8("design:paramtypes", [
2834
- typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
2835
- typeof import_common38.Logger === "undefined" ? Object : import_common38.Logger
2836
- ])
2837
- ], LoggerService2);
2838
-
2839
- // src/logger/middleware/correlation-id.middleware.ts
2840
- var import_common39 = require("@nestjs/common");
2841
- function _ts_decorate15(decorators, target, key, desc) {
2842
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2843
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2844
- 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;
2845
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2846
- }
2847
- __name(_ts_decorate15, "_ts_decorate");
2848
- function _ts_metadata9(k, v) {
2849
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2850
- }
2851
- __name(_ts_metadata9, "_ts_metadata");
2852
- var CorrelationIdMiddleware = class {
2853
- static {
2854
- __name(this, "CorrelationIdMiddleware");
2855
- }
2856
- includeInResponse;
2857
- responseHeader;
2858
- constructor(options = {}) {
2859
- this.includeInResponse = options.includeInResponse ?? true;
2860
- this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
2861
- }
2862
- /**
2863
- * Middleware handler for processing requests.
2864
- */
2865
- use(req, reply, next) {
2866
- const correlationId = generateCorrelationId();
2867
- if (this.includeInResponse) {
2868
- addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2869
- }
2870
- runWithCorrelationContext({
2871
- correlationId
2872
- }, () => {
2873
- next();
2874
- });
2875
- }
2876
- /**
2877
- * Fastify hook handler for onRequest.
2878
- * This is an async function that returns a Promise, ensuring the AsyncLocalStorage
2879
- * context persists throughout the entire request lifecycle.
2880
- */
2881
- async onRequest(req, reply) {
2882
- const correlationId = generateCorrelationId();
2883
- if (this.includeInResponse) {
2884
- addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2885
- }
2886
- const store = correlationStorage.getStore();
2887
- if (!store) {
2888
- correlationStorage.enterWith({
2889
- correlationId
2890
- });
2891
- }
2892
- }
2893
- };
2894
- CorrelationIdMiddleware = _ts_decorate15([
2895
- (0, import_common39.Injectable)(),
2896
- _ts_metadata9("design:type", Function),
2897
- _ts_metadata9("design:paramtypes", [
2898
- typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
2899
- ])
2900
- ], CorrelationIdMiddleware);
2901
-
2902
- // src/logger/interceptors/http-logger.interceptor.ts
2903
- var import_common40 = require("@nestjs/common");
2904
- var import_operators2 = require("rxjs/operators");
2905
- function _ts_decorate16(decorators, target, key, desc) {
2906
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2907
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2908
- 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;
2909
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2910
- }
2911
- __name(_ts_decorate16, "_ts_decorate");
2912
- function _ts_metadata10(k, v) {
2913
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2914
- }
2915
- __name(_ts_metadata10, "_ts_metadata");
2916
- function _ts_param5(paramIndex, decorator) {
2917
- return function(target, key) {
2918
- decorator(target, key, paramIndex);
2919
- };
2920
- }
2921
- __name(_ts_param5, "_ts_param");
2922
- var HttpLoggerInterceptor = class {
2923
- static {
2924
- __name(this, "HttpLoggerInterceptor");
2925
- }
2926
- logger;
2927
- enableRequestLog;
2928
- enableResponseLog;
2929
- slowRequestThreshold;
2930
- constructor(logger, options) {
2931
- this.logger = logger;
2932
- this.enableRequestLog = options?.enableRequestLog ?? true;
2933
- this.enableResponseLog = options?.enableResponseLog ?? true;
2934
- this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
2935
- }
2936
- intercept(context, next) {
2937
- if (context.getType() !== "http") {
2938
- return next.handle();
2939
- }
2940
- const httpContext = context.switchToHttp();
2941
- const request = httpContext.getRequest();
2942
- const response = httpContext.getResponse();
2943
- const startTime = Date.now();
2944
- if (this.enableRequestLog) {
2945
- this.logRequest(request);
2946
- }
2947
- return next.handle().pipe((0, import_operators2.tap)(() => {
2948
- if (this.enableResponseLog) {
2949
- const duration = Date.now() - startTime;
2950
- this.logResponse(request, response, duration);
2951
- }
2952
- }), (0, import_operators2.catchError)((error) => {
2953
- const duration = Date.now() - startTime;
2954
- this.logError(request, response, duration, error);
2955
- throw error;
2956
- }));
2957
- }
2958
- logRequest(request) {
2959
- try {
2960
- const correlationContext = getCorrelationContext();
2961
- const metadata = {
2962
- type: "http_request",
2963
- method: request.method,
2964
- url: request.url,
2965
- correlationId: correlationContext?.correlationId,
2966
- ip: request.ip,
2967
- userAgent: request.headers["user-agent"]
2968
- };
2969
- this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
2970
- } catch (error) {
2971
- this.logger.error("Failed to log HTTP request", error.stack);
2972
- }
2973
- }
2974
- logResponse(request, response, duration) {
2975
- try {
2976
- const correlationContext = getCorrelationContext();
2977
- const statusCode = response.statusCode;
2978
- const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
2979
- const metadata = {
2980
- type: "http_response",
2981
- method: request.method,
2982
- url: request.url,
2983
- statusCode,
2984
- duration,
2985
- correlationId: correlationContext?.correlationId
2986
- };
2987
- if (duration > this.slowRequestThreshold) {
2988
- metadata.slowRequest = true;
2989
- }
2990
- const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
2991
- this.logger.logWithMetadata(logLevel, message, metadata);
2992
- } catch (error) {
2993
- this.logger.error("Failed to log HTTP response", error.stack);
2994
- }
2995
- }
2996
- logError(request, response, duration, error) {
2997
- try {
2998
- const correlationContext = getCorrelationContext();
2999
- const statusCode = response.statusCode || 500;
3000
- const metadata = {
3001
- type: "http_error",
3002
- method: request.method,
3003
- url: request.url,
3004
- statusCode,
3005
- duration,
3006
- correlationId: correlationContext?.correlationId,
3007
- errorName: error?.name || "Error",
3008
- errorMessage: error?.message || "Unknown error"
3009
- };
3010
- if (error?.stack) {
3011
- metadata.trace = error.stack;
3012
- }
3013
- if (error?.response) {
3014
- metadata.errorDetails = error.response;
3015
- }
3016
- const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
3017
- this.logger.logWithMetadata("error", message, metadata);
3018
- } catch (loggingError) {
3019
- this.logger.error("Failed to log HTTP error", loggingError.stack);
3020
- }
3021
- }
3022
- };
3023
- HttpLoggerInterceptor = _ts_decorate16([
3004
+ LoggerService2 = _ts_decorate16([
3024
3005
  (0, import_common40.Injectable)(),
3006
+ _ts_param5(0, (0, import_common40.Optional)()),
3025
3007
  _ts_param5(1, (0, import_common40.Optional)()),
3026
- _ts_metadata10("design:type", Function),
3027
- _ts_metadata10("design:paramtypes", [
3028
- typeof LoggerService === "undefined" ? Object : LoggerService,
3029
- typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
3008
+ _ts_metadata9("design:type", Function),
3009
+ _ts_metadata9("design:paramtypes", [
3010
+ typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
3011
+ typeof Logger === "undefined" ? Object : Logger
3030
3012
  ])
3031
- ], HttpLoggerInterceptor);
3013
+ ], LoggerService2);
3032
3014
 
3033
3015
  // src/logger/logger.module.ts
3034
3016
  function _ts_decorate17(decorators, target, key, desc) {
@@ -3301,7 +3283,7 @@ var LoggerModule = class _LoggerModule {
3301
3283
  * ```
3302
3284
  */
3303
3285
  static forRootAsync(options) {
3304
- const asyncProviders = this.createAsyncProviders(options);
3286
+ const asyncProviders = _LoggerModule.createAsyncProviders(options);
3305
3287
  return {
3306
3288
  module: _LoggerModule,
3307
3289
  imports: options.imports || [],
@@ -3377,7 +3359,7 @@ var LoggerModule = class _LoggerModule {
3377
3359
  * Configures middleware for the module.
3378
3360
  * Middleware is registered globally in main.ts using Fastify hooks.
3379
3361
  */
3380
- configure(consumer) {
3362
+ configure(_consumer) {
3381
3363
  }
3382
3364
  /**
3383
3365
  * Creates async providers for dynamic module configuration.
@@ -3385,11 +3367,11 @@ var LoggerModule = class _LoggerModule {
3385
3367
  static createAsyncProviders(options) {
3386
3368
  if (options.useFactory) {
3387
3369
  return [
3388
- this.createAsyncOptionsProvider(options)
3370
+ _LoggerModule.createAsyncOptionsProvider(options)
3389
3371
  ];
3390
3372
  }
3391
3373
  const providers = [
3392
- this.createAsyncOptionsProvider(options)
3374
+ _LoggerModule.createAsyncOptionsProvider(options)
3393
3375
  ];
3394
3376
  if (options.useClass) {
3395
3377
  providers.push({
@@ -3407,7 +3389,7 @@ var LoggerModule = class _LoggerModule {
3407
3389
  return {
3408
3390
  provide: LOGGER_MODULE_OPTIONS,
3409
3391
  useFactory: /* @__PURE__ */ __name(async (...args) => {
3410
- const userOptions = await options.useFactory(...args);
3392
+ const userOptions = await options.useFactory?.(...args);
3411
3393
  return mergeWithDefaults(userOptions);
3412
3394
  }, "useFactory"),
3413
3395
  inject: options.inject || []