@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.js CHANGED
@@ -1,6 +1,19 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
+ // src/auth/auth-config.module.ts
5
+ import { Global as Global2, Module as Module2 } from "@nestjs/common";
6
+ import { ConfigModule, ConfigService as ConfigService2 } from "@nestjs/config";
7
+ import { APP_GUARD } from "@nestjs/core";
8
+ import { JwtModule } from "@nestjs/jwt";
9
+
10
+ // src/request/request.module.ts
11
+ import { Global, Module } from "@nestjs/common";
12
+
13
+ // src/request/services/request.service.ts
14
+ import { Inject, Injectable, Scope } from "@nestjs/common";
15
+ import { REQUEST } from "@nestjs/core";
16
+
4
17
  // src/config/index.ts
5
18
  var defaultConfig = {
6
19
  cookie: {
@@ -75,31 +88,7 @@ function getJwtExpiry() {
75
88
  }
76
89
  __name(getJwtExpiry, "getJwtExpiry");
77
90
 
78
- // src/auth/utils/token-hash.util.ts
79
- import * as crypto from "crypto";
80
- function hashToken(token) {
81
- return crypto.createHash("sha256").update(token).digest("hex");
82
- }
83
- __name(hashToken, "hashToken");
84
- function verifyTokenHash(token, expectedHash) {
85
- const computedHash = hashToken(token);
86
- if (computedHash.length !== expectedHash.length) return false;
87
- return crypto.timingSafeEqual(Buffer.from(computedHash, "hex"), Buffer.from(expectedHash, "hex"));
88
- }
89
- __name(verifyTokenHash, "verifyTokenHash");
90
-
91
- // src/auth/auth-config.module.ts
92
- import { Global as Global2, Module as Module2 } from "@nestjs/common";
93
- import { ConfigModule, ConfigService as ConfigService2 } from "@nestjs/config";
94
- import { APP_GUARD } from "@nestjs/core";
95
- import { JwtModule } from "@nestjs/jwt";
96
-
97
- // src/request/request.module.ts
98
- import { Global, Module } from "@nestjs/common";
99
-
100
91
  // src/request/services/request.service.ts
101
- import { Inject, Injectable, Scope } from "@nestjs/common";
102
- import { REQUEST } from "@nestjs/core";
103
92
  function _ts_decorate(decorators, target, key, desc) {
104
93
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
105
94
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -117,7 +106,7 @@ function _ts_param(paramIndex, decorator) {
117
106
  };
118
107
  }
119
108
  __name(_ts_param, "_ts_param");
120
- var RequestService = class {
109
+ var RequestService2 = class {
121
110
  static {
122
111
  __name(this, "RequestService");
123
112
  }
@@ -166,7 +155,7 @@ var RequestService = class {
166
155
  }
167
156
  }
168
157
  return null;
169
- } catch (error) {
158
+ } catch (_error) {
170
159
  return null;
171
160
  }
172
161
  }
@@ -186,7 +175,7 @@ var RequestService = class {
186
175
  return this.request.headers || {};
187
176
  }
188
177
  };
189
- RequestService = _ts_decorate([
178
+ RequestService2 = _ts_decorate([
190
179
  Injectable({
191
180
  scope: Scope.REQUEST
192
181
  }),
@@ -195,7 +184,7 @@ RequestService = _ts_decorate([
195
184
  _ts_metadata("design:paramtypes", [
196
185
  typeof FastifyRequest === "undefined" ? Object : FastifyRequest
197
186
  ])
198
- ], RequestService);
187
+ ], RequestService2);
199
188
 
200
189
  // src/request/request.module.ts
201
190
  function _ts_decorate2(decorators, target, key, desc) {
@@ -214,30 +203,31 @@ RequestModule = _ts_decorate2([
214
203
  Global(),
215
204
  Module({
216
205
  providers: [
217
- RequestService
206
+ RequestService2
218
207
  ],
219
208
  exports: [
220
- RequestService
209
+ RequestService2
221
210
  ]
222
211
  })
223
212
  ], RequestModule);
224
213
 
225
214
  // src/auth/guards/vritti-auth.guard.ts
226
- import { Injectable as Injectable3, Logger as Logger2, Scope as Scope2, UnauthorizedException } from "@nestjs/common";
227
- import { ConfigService } from "@nestjs/config";
228
- import { Reflector } from "@nestjs/core";
229
- import { JwtService } from "@nestjs/jwt";
230
-
231
- // src/database/services/primary-database.service.ts
232
- import { Inject as Inject2, Injectable as Injectable2, InternalServerErrorException, Logger } from "@nestjs/common";
233
- import { Pool } from "pg";
234
- import { drizzle } from "drizzle-orm/node-postgres";
235
- import { eq, or } from "drizzle-orm";
215
+ import { Injectable as Injectable2, Logger as Logger2, Scope as Scope2, UnauthorizedException } from "@nestjs/common";
236
216
 
237
- // src/database/constants.ts
238
- var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
217
+ // src/auth/utils/token-hash.util.ts
218
+ import * as crypto from "crypto";
219
+ function hashToken(token) {
220
+ return crypto.createHash("sha256").update(token).digest("hex");
221
+ }
222
+ __name(hashToken, "hashToken");
223
+ function verifyTokenHash(token, expectedHash) {
224
+ const computedHash = hashToken(token);
225
+ if (computedHash.length !== expectedHash.length) return false;
226
+ return crypto.timingSafeEqual(Buffer.from(computedHash, "hex"), Buffer.from(expectedHash, "hex"));
227
+ }
228
+ __name(verifyTokenHash, "verifyTokenHash");
239
229
 
240
- // src/database/services/primary-database.service.ts
230
+ // src/auth/guards/vritti-auth.guard.ts
241
231
  function _ts_decorate3(decorators, target, key, desc) {
242
232
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
243
233
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -249,491 +239,658 @@ function _ts_metadata2(k, v) {
249
239
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
250
240
  }
251
241
  __name(_ts_metadata2, "_ts_metadata");
252
- function _ts_param2(paramIndex, decorator) {
253
- return function(target, key) {
254
- decorator(target, key, paramIndex);
255
- };
256
- }
257
- __name(_ts_param2, "_ts_param");
258
- var PrimaryDatabaseService = class _PrimaryDatabaseService {
242
+ var VrittiAuthGuard = class _VrittiAuthGuard {
259
243
  static {
260
- __name(this, "PrimaryDatabaseService");
244
+ __name(this, "VrittiAuthGuard");
261
245
  }
262
- options;
263
- logger = new Logger(_PrimaryDatabaseService.name);
264
- /** PostgreSQL connection pool */
265
- pool = null;
266
- /** Drizzle database instance */
267
- db = null;
268
- /** In-memory cache: Map<tenantIdentifier, TenantConfig> */
269
- tenantConfigCache = /* @__PURE__ */ new Map();
270
- /** Cache TTL in milliseconds */
271
- cacheTTL;
272
- constructor(options) {
273
- this.options = options;
274
- this.cacheTTL = options.connectionCacheTTL || 3e5;
246
+ reflector;
247
+ _configService;
248
+ jwtService;
249
+ primaryDatabase;
250
+ requestService;
251
+ logger = new Logger2(_VrittiAuthGuard.name);
252
+ constructor(reflector, _configService, jwtService, primaryDatabase, requestService) {
253
+ this.reflector = reflector;
254
+ this._configService = _configService;
255
+ this.jwtService = jwtService;
256
+ this.primaryDatabase = primaryDatabase;
257
+ this.requestService = requestService;
275
258
  }
276
- async onModuleInit() {
277
- if (this.options.primaryDb) {
278
- await this.initializeDrizzleClient();
259
+ async canActivate(context) {
260
+ const request = context.switchToHttp().getRequest();
261
+ const isPublic = this.reflector.getAllAndOverride("isPublic", [
262
+ context.getHandler(),
263
+ context.getClass()
264
+ ]);
265
+ if (isPublic) {
266
+ this.logger.debug("Public endpoint detected, skipping authentication");
267
+ return true;
268
+ }
269
+ const isOnboarding = this.reflector.getAllAndOverride("isOnboarding", [
270
+ context.getHandler(),
271
+ context.getClass()
272
+ ]);
273
+ try {
274
+ const accessToken = this.requestService.getAccessToken();
275
+ if (!accessToken) {
276
+ this.logger.warn("Access token not found in Authorization header");
277
+ throw new UnauthorizedException("Access token not found");
278
+ }
279
+ const decodedToken = this.jwtService.decode(accessToken);
280
+ if (!decodedToken) {
281
+ this.logger.warn("Failed to decode access token");
282
+ throw new UnauthorizedException("Invalid token format");
283
+ }
284
+ if (isOnboarding) {
285
+ if (decodedToken.type !== "onboarding") {
286
+ this.logger.warn("Onboarding endpoint requires onboarding token");
287
+ throw new UnauthorizedException("This endpoint requires an onboarding token");
288
+ }
289
+ const validatedToken2 = this.validateAccessToken(accessToken);
290
+ this.logger.debug("Onboarding token validated successfully");
291
+ this.validateRefreshTokenBinding(context, validatedToken2);
292
+ const userId2 = validatedToken2.userId;
293
+ request.user = {
294
+ id: userId2
295
+ };
296
+ return true;
297
+ }
298
+ if (decodedToken.type === "onboarding") {
299
+ this.logger.warn("Regular endpoint accessed with onboarding token");
300
+ throw new UnauthorizedException("Onboarding tokens cannot access this endpoint");
301
+ }
302
+ const validatedToken = this.validateAccessToken(accessToken);
303
+ this.logger.debug("Access token validated successfully");
304
+ this.validateRefreshTokenBinding(context, validatedToken);
305
+ const userId = validatedToken.userId;
306
+ request.user = {
307
+ id: userId
308
+ };
309
+ const tenantIdentifier = this.requestService.getTenantIdentifier();
310
+ if (!tenantIdentifier) {
311
+ this.logger.warn("Tenant identifier not found in request");
312
+ throw new UnauthorizedException("Tenant identifier not found");
313
+ }
314
+ this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
315
+ if (tenantIdentifier === "cloud") {
316
+ this.logger.debug("Platform admin access detected, skipping tenant database validation");
317
+ return true;
318
+ }
319
+ const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
320
+ if (!tenantInfo) {
321
+ this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
322
+ throw new UnauthorizedException("Invalid tenant");
323
+ }
324
+ if (tenantInfo.status !== "ACTIVE") {
325
+ this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
326
+ throw new UnauthorizedException(`Tenant is ${tenantInfo.status}`);
327
+ }
328
+ this.logger.debug(`Tenant validated: ${tenantInfo.subdomain} (${tenantInfo.type})`);
329
+ return true;
330
+ } catch (error) {
331
+ if (error instanceof UnauthorizedException) {
332
+ throw error;
333
+ }
334
+ this.logger.error("Unexpected error in auth guard", error);
335
+ throw new UnauthorizedException("Authentication failed");
279
336
  }
280
337
  }
281
338
  /**
282
- * Initialize connection to primary database using Drizzle
339
+ * Validate access token with proper expiry checks
340
+ * Throws UnauthorizedException if token is invalid or expired
283
341
  */
284
- async initializeDrizzleClient() {
342
+ validateAccessToken(token) {
285
343
  try {
286
- const databaseUrl = this.buildPrimaryDbUrl();
287
- this.pool = new Pool({
288
- connectionString: databaseUrl,
289
- max: this.options.maxConnections || 10
290
- });
291
- this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
292
- this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
293
- this.db = drizzle({
294
- client: this.pool,
295
- schema: this.options.drizzleSchema,
296
- relations: this.options.drizzleRelations
297
- });
298
- this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
299
- await this.pool.query("SELECT 1");
300
- this.logger.log("Connected to primary database (tenant registry)");
344
+ const decoded = this.jwtService.verify(token);
345
+ this.logger.debug(`Access token decoded for user: ${decoded.userId}`);
346
+ if (decoded.exp) {
347
+ const expiryTime = decoded.exp * 1e3;
348
+ const currentTime = Date.now();
349
+ const timeRemaining = expiryTime - currentTime;
350
+ this.logger.debug(`Access token valid for ${Math.floor(timeRemaining / 1e3)} more seconds`);
351
+ }
352
+ return decoded;
301
353
  } catch (error) {
302
- this.logger.error("Failed to connect to primary database", error);
303
- throw new InternalServerErrorException("Failed to initialize tenant registry");
354
+ if (error instanceof UnauthorizedException) {
355
+ throw error;
356
+ }
357
+ const jwtError = error;
358
+ if (jwtError?.name === "TokenExpiredError") {
359
+ this.logger.warn(`Access token expired at: ${jwtError?.expiredAt}`);
360
+ throw new UnauthorizedException("Access token has expired");
361
+ }
362
+ if (jwtError?.name === "JsonWebTokenError") {
363
+ this.logger.warn(`Access token verification failed: ${jwtError?.message}`);
364
+ throw new UnauthorizedException("Invalid access token");
365
+ }
366
+ if (jwtError?.name === "NotBeforeError") {
367
+ this.logger.warn("Access token used before valid (nbf claim)");
368
+ throw new UnauthorizedException("Access token not yet valid");
369
+ }
370
+ this.logger.error("Unexpected error validating access token", error);
371
+ throw new UnauthorizedException("Access token validation failed");
304
372
  }
305
373
  }
306
374
  /**
307
- * Build connection URL from primary database properties
375
+ * Validate that the access token is bound to the refresh token in the cookie.
376
+ * This prevents token theft - a stolen access token is useless without the
377
+ * corresponding refresh token cookie.
378
+ *
379
+ * @param context - The execution context containing the request
380
+ * @param validatedToken - The decoded and validated JWT token
381
+ * @throws UnauthorizedException if token binding validation fails
308
382
  */
309
- buildPrimaryDbUrl() {
310
- if (!this.options.primaryDb) {
311
- throw new Error("Primary database configuration not provided");
383
+ validateRefreshTokenBinding(context, validatedToken) {
384
+ const config = getConfig();
385
+ if (!config.jwt.validateTokenBinding) {
386
+ this.logger.debug("Token binding validation is disabled");
387
+ return;
312
388
  }
313
- const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
314
- let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
315
- const params = new URLSearchParams();
316
- if (schema) {
317
- params.set("schema", schema);
389
+ if (!validatedToken.refreshTokenHash) {
390
+ this.logger.debug("Token does not contain refreshTokenHash, skipping binding validation");
391
+ return;
318
392
  }
319
- params.set("sslmode", sslMode);
320
- const queryString = params.toString();
321
- if (queryString) {
322
- url += `?${queryString}`;
393
+ const request = context.switchToHttp().getRequest();
394
+ const cookies = request.cookies || {};
395
+ const refreshToken = cookies[config.cookie.refreshCookieName];
396
+ if (!refreshToken) {
397
+ this.logger.warn("Session validation failed - refresh token cookie not found");
398
+ throw new UnauthorizedException("Session validation failed");
323
399
  }
324
- this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
325
- return url;
326
- }
327
- /**
328
- * Mask password in connection URL for logging
329
- */
330
- maskPassword(url) {
331
- return url.replace(/:([^@]+)@/, ":****@");
332
- }
333
- /**
334
- * Get tenant configuration by identifier (ID or subdomain)
335
- *
336
- * @param tenantIdentifier Tenant ID or subdomain
337
- * @returns Tenant configuration or null if not found
338
- */
339
- async getTenantInfo(tenantIdentifier) {
340
- const cached = this.tenantConfigCache.get(tenantIdentifier);
341
- if (cached) {
342
- this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
343
- return cached;
344
- }
345
- try {
346
- if (!this.db) {
347
- throw new Error("Primary database client not initialized");
348
- }
349
- this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
350
- const schema = this.options.drizzleSchema;
351
- const { tenants, tenantDatabaseConfigs } = schema;
352
- const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, eq(tenants.id, tenantDatabaseConfigs.tenantId)).where(or(eq(tenants.id, tenantIdentifier), eq(tenants.subdomain, tenantIdentifier))).limit(1);
353
- if (!result.length) {
354
- this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
355
- return null;
356
- }
357
- const row = result[0];
358
- const tenant = row.tenants;
359
- const config = row.tenant_database_configs;
360
- if (tenant.status !== "ACTIVE") {
361
- this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
362
- return null;
363
- }
364
- const info = {
365
- id: tenant.id,
366
- subdomain: tenant.subdomain,
367
- type: tenant.dbType,
368
- status: tenant.status,
369
- // For SHARED tenants: schema name
370
- schemaName: config?.dbSchema || void 0,
371
- // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
372
- databaseName: config?.dbName || void 0,
373
- databaseHost: config?.dbHost || void 0,
374
- databasePort: config?.dbPort || void 0,
375
- databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
376
- databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
377
- databaseSslMode: config?.dbSslMode || void 0,
378
- connectionPoolSize: config?.connectionPoolSize || void 0
379
- };
380
- this.cacheInfo(info);
381
- return info;
382
- } catch (error) {
383
- this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
384
- throw new InternalServerErrorException("Failed to resolve tenant");
385
- }
386
- }
387
- /**
388
- * Cache tenant information with TTL
389
- */
390
- cacheInfo(info) {
391
- this.tenantConfigCache.set(info.id, info);
392
- this.tenantConfigCache.set(info.subdomain, info);
393
- setTimeout(() => {
394
- this.tenantConfigCache.delete(info.id);
395
- this.tenantConfigCache.delete(info.subdomain);
396
- this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
397
- }, this.cacheTTL);
398
- }
399
- /**
400
- * Clear cached tenant information
401
- *
402
- * Useful when tenant settings are updated and cache needs to be invalidated
403
- *
404
- * @param tenantIdentifier Tenant ID or subdomain
405
- */
406
- clearTenantCache(tenantIdentifier) {
407
- const config = this.tenantConfigCache.get(tenantIdentifier);
408
- if (config) {
409
- this.tenantConfigCache.delete(config.id);
410
- this.tenantConfigCache.delete(config.subdomain);
411
- this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
412
- }
413
- }
414
- /**
415
- * Clear all cached tenant configurations
416
- */
417
- clearAllCaches() {
418
- const size = this.tenantConfigCache.size;
419
- this.tenantConfigCache.clear();
420
- this.logger.log(`Cleared ${size} cached tenant configs`);
421
- }
422
- /**
423
- * Get the Drizzle database instance for the primary database.
424
- * This is a synchronous property that returns the initialized Drizzle client.
425
- *
426
- * @returns Primary database Drizzle instance
427
- * @throws Error if primary database client is not initialized
428
- */
429
- get drizzleClient() {
430
- if (!this.db) {
431
- throw new Error("Primary database client not initialized");
400
+ if (!verifyTokenHash(refreshToken, validatedToken.refreshTokenHash)) {
401
+ this.logger.warn("Session validation failed - token binding mismatch");
402
+ throw new UnauthorizedException("Session validation failed");
432
403
  }
433
- return this.db;
404
+ this.logger.debug("Token binding validated successfully");
434
405
  }
435
- /**
436
- * Get the Drizzle schema
437
- */
438
- get schema() {
439
- return this.options.drizzleSchema;
406
+ };
407
+ VrittiAuthGuard = _ts_decorate3([
408
+ Injectable2({
409
+ scope: Scope2.REQUEST
410
+ }),
411
+ _ts_metadata2("design:type", Function),
412
+ _ts_metadata2("design:paramtypes", [
413
+ typeof Reflector === "undefined" ? Object : Reflector,
414
+ typeof ConfigService === "undefined" ? Object : ConfigService,
415
+ typeof JwtService === "undefined" ? Object : JwtService,
416
+ typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
417
+ typeof RequestService === "undefined" ? Object : RequestService
418
+ ])
419
+ ], VrittiAuthGuard);
420
+
421
+ // src/auth/auth-config.module.ts
422
+ function _ts_decorate4(decorators, target, key, desc) {
423
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
424
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
425
+ 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;
426
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
427
+ }
428
+ __name(_ts_decorate4, "_ts_decorate");
429
+ var AuthConfigModule = class _AuthConfigModule {
430
+ static {
431
+ __name(this, "AuthConfigModule");
440
432
  }
441
433
  /**
442
- * Decrypt database credentials
434
+ * Register the auth module with async configuration
443
435
  *
444
- * Override this method to implement your encryption strategy
436
+ * This method:
437
+ * 1. Configures JwtModule with JWT_SECRET from ConfigService
438
+ * 2. Provides VrittiAuthGuard globally (applies to all routes)
439
+ * 3. Exports JwtModule for use in other modules (e.g., for signing tokens)
445
440
  *
446
- * @param encrypted Encrypted value
447
- * @returns Decrypted value
441
+ * @returns Dynamic module configuration
448
442
  */
449
- decrypt(encrypted) {
450
- return encrypted;
451
- }
452
- async onModuleDestroy() {
453
- if (this.pool) {
454
- await this.pool.end();
455
- this.logger.log("Disconnected from primary database");
456
- }
443
+ static forRootAsync() {
444
+ return {
445
+ module: _AuthConfigModule,
446
+ imports: [
447
+ ConfigModule,
448
+ RequestModule,
449
+ JwtModule.registerAsync({
450
+ imports: [
451
+ ConfigModule
452
+ ],
453
+ inject: [
454
+ ConfigService2
455
+ ],
456
+ useFactory: /* @__PURE__ */ __name((config) => ({
457
+ secret: config.get("JWT_SECRET"),
458
+ signOptions: {
459
+ algorithm: "HS256"
460
+ }
461
+ }), "useFactory")
462
+ })
463
+ ],
464
+ providers: [
465
+ {
466
+ provide: APP_GUARD,
467
+ useClass: VrittiAuthGuard
468
+ }
469
+ ],
470
+ exports: [
471
+ JwtModule
472
+ ]
473
+ };
457
474
  }
458
475
  };
459
- PrimaryDatabaseService = _ts_decorate3([
460
- Injectable2(),
461
- _ts_param2(0, Inject2(DATABASE_MODULE_OPTIONS)),
462
- _ts_metadata2("design:type", Function),
463
- _ts_metadata2("design:paramtypes", [
464
- typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
465
- ])
466
- ], PrimaryDatabaseService);
476
+ AuthConfigModule = _ts_decorate4([
477
+ Global2(),
478
+ Module2({})
479
+ ], AuthConfigModule);
467
480
 
468
- // src/auth/guards/vritti-auth.guard.ts
469
- function _ts_decorate4(decorators, target, key, desc) {
481
+ // src/auth/decorators/onboarding.decorator.ts
482
+ import { SetMetadata } from "@nestjs/common";
483
+ var Onboarding = /* @__PURE__ */ __name(() => SetMetadata("isOnboarding", true), "Onboarding");
484
+
485
+ // src/auth/decorators/public.decorator.ts
486
+ import { SetMetadata as SetMetadata2 } from "@nestjs/common";
487
+ var Public = /* @__PURE__ */ __name(() => SetMetadata2("isPublic", true), "Public");
488
+
489
+ // src/database/database.module.ts
490
+ import { Global as Global3, Module as Module3 } from "@nestjs/common";
491
+ import { APP_INTERCEPTOR } from "@nestjs/core";
492
+
493
+ // src/database/constants.ts
494
+ var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
495
+
496
+ // src/database/interceptors/message-tenant-context.interceptor.ts
497
+ import { Injectable as Injectable3, Logger as Logger3, Scope as Scope3 } from "@nestjs/common";
498
+ import { tap } from "rxjs/operators";
499
+ function _ts_decorate5(decorators, target, key, desc) {
470
500
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
471
501
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
472
502
  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;
473
503
  return c > 3 && r && Object.defineProperty(target, key, r), r;
474
504
  }
475
- __name(_ts_decorate4, "_ts_decorate");
505
+ __name(_ts_decorate5, "_ts_decorate");
476
506
  function _ts_metadata3(k, v) {
477
507
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
478
508
  }
479
509
  __name(_ts_metadata3, "_ts_metadata");
480
- var VrittiAuthGuard = class _VrittiAuthGuard {
510
+ var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
481
511
  static {
482
- __name(this, "VrittiAuthGuard");
512
+ __name(this, "MessageTenantContextInterceptor");
483
513
  }
484
- reflector;
485
- configService;
486
- jwtService;
487
- primaryDatabase;
488
- requestService;
489
- logger = new Logger2(_VrittiAuthGuard.name);
490
- constructor(reflector, configService, jwtService, primaryDatabase, requestService) {
491
- this.reflector = reflector;
492
- this.configService = configService;
493
- this.jwtService = jwtService;
494
- this.primaryDatabase = primaryDatabase;
495
- this.requestService = requestService;
514
+ tenantContext;
515
+ logger = new Logger3(_MessageTenantContextInterceptor.name);
516
+ constructor(tenantContext) {
517
+ this.tenantContext = tenantContext;
496
518
  }
497
- async canActivate(context) {
498
- const request = context.switchToHttp().getRequest();
499
- const isPublic = this.reflector.getAllAndOverride("isPublic", [
500
- context.getHandler(),
501
- context.getClass()
502
- ]);
503
- if (isPublic) {
504
- this.logger.debug("Public endpoint detected, skipping authentication");
505
- return true;
506
- }
507
- const isOnboarding = this.reflector.getAllAndOverride("isOnboarding", [
508
- context.getHandler(),
509
- context.getClass()
510
- ]);
511
- try {
512
- const accessToken = this.requestService.getAccessToken();
513
- if (!accessToken) {
514
- this.logger.warn("Access token not found in Authorization header");
515
- throw new UnauthorizedException("Access token not found");
516
- }
517
- const decodedToken = this.jwtService.decode(accessToken);
518
- if (!decodedToken) {
519
- this.logger.warn("Failed to decode access token");
520
- throw new UnauthorizedException("Invalid token format");
521
- }
522
- if (isOnboarding) {
523
- if (decodedToken.type !== "onboarding") {
524
- this.logger.warn("Onboarding endpoint requires onboarding token");
525
- throw new UnauthorizedException("This endpoint requires an onboarding token");
519
+ intercept(context, next) {
520
+ const contextType = context.getType();
521
+ if (contextType === "rpc") {
522
+ const rpcContext = context.switchToRpc();
523
+ const payload = rpcContext.getData();
524
+ if (payload?.tenant) {
525
+ const tenant = payload.tenant;
526
+ this.logger.debug(`Setting tenant context from message: ${tenant.subdomain}`);
527
+ try {
528
+ this.tenantContext.setTenant(tenant);
529
+ this.logger.log(`Tenant context set: ${tenant.subdomain} (${tenant.type})`);
530
+ } catch (error) {
531
+ this.logger.error("Failed to set tenant context from message", error);
526
532
  }
527
- const validatedToken2 = this.validateAccessToken(accessToken);
528
- this.logger.debug("Onboarding token validated successfully");
529
- this.validateRefreshTokenBinding(context, validatedToken2);
530
- const userId2 = validatedToken2.userId;
531
- request.user = {
532
- id: userId2
533
- };
534
- return true;
535
- }
536
- if (decodedToken.type === "onboarding") {
537
- this.logger.warn("Regular endpoint accessed with onboarding token");
538
- throw new UnauthorizedException("Onboarding tokens cannot access this endpoint");
533
+ } else {
534
+ this.logger.warn("Message payload missing tenant information");
539
535
  }
540
- const validatedToken = this.validateAccessToken(accessToken);
541
- this.logger.debug("Access token validated successfully");
542
- this.validateRefreshTokenBinding(context, validatedToken);
543
- const userId = validatedToken.userId;
544
- request.user = {
545
- id: userId
546
- };
536
+ }
537
+ return next.handle().pipe(tap({
538
+ next: /* @__PURE__ */ __name(() => {
539
+ this.cleanupContext();
540
+ }, "next"),
541
+ error: /* @__PURE__ */ __name(() => {
542
+ this.cleanupContext();
543
+ }, "error"),
544
+ complete: /* @__PURE__ */ __name(() => {
545
+ this.cleanupContext();
546
+ }, "complete")
547
+ }));
548
+ }
549
+ /**
550
+ * Clean up tenant context after message is processed
551
+ */
552
+ cleanupContext() {
553
+ if (this.tenantContext.hasTenant()) {
554
+ const tenant = this.tenantContext.getTenantIdSafe();
555
+ this.tenantContext.clearTenant();
556
+ this.logger.debug(`Cleaned up tenant context: ${tenant}`);
557
+ }
558
+ }
559
+ };
560
+ MessageTenantContextInterceptor = _ts_decorate5([
561
+ Injectable3({
562
+ scope: Scope3.REQUEST
563
+ }),
564
+ _ts_metadata3("design:type", Function),
565
+ _ts_metadata3("design:paramtypes", [
566
+ typeof TenantContextService === "undefined" ? Object : TenantContextService
567
+ ])
568
+ ], MessageTenantContextInterceptor);
569
+
570
+ // src/database/interceptors/tenant-context.interceptor.ts
571
+ import { Injectable as Injectable4, Logger as Logger4, Scope as Scope4, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
572
+ function _ts_decorate6(decorators, target, key, desc) {
573
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
574
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
575
+ 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;
576
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
577
+ }
578
+ __name(_ts_decorate6, "_ts_decorate");
579
+ function _ts_metadata4(k, v) {
580
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
581
+ }
582
+ __name(_ts_metadata4, "_ts_metadata");
583
+ var TenantContextInterceptor = class _TenantContextInterceptor {
584
+ static {
585
+ __name(this, "TenantContextInterceptor");
586
+ }
587
+ reflector;
588
+ tenantContext;
589
+ primaryDatabase;
590
+ requestService;
591
+ logger = new Logger4(_TenantContextInterceptor.name);
592
+ constructor(reflector, tenantContext, primaryDatabase, requestService) {
593
+ this.reflector = reflector;
594
+ this.tenantContext = tenantContext;
595
+ this.primaryDatabase = primaryDatabase;
596
+ this.requestService = requestService;
597
+ }
598
+ async intercept(context, next) {
599
+ const request = context.switchToHttp().getRequest();
600
+ this.logger.debug(`Processing request: ${request.method} ${request.url}`);
601
+ const isPublic = this.reflector.getAllAndOverride("isPublic", [
602
+ context.getHandler(),
603
+ context.getClass()
604
+ ]);
605
+ try {
547
606
  const tenantIdentifier = this.requestService.getTenantIdentifier();
607
+ if (isPublic && !tenantIdentifier) {
608
+ this.logger.debug("Public endpoint without tenant identifier, skipping tenant context setup");
609
+ return next.handle();
610
+ }
548
611
  if (!tenantIdentifier) {
549
- this.logger.warn("Tenant identifier not found in request");
550
- throw new UnauthorizedException("Tenant identifier not found");
612
+ throw new UnauthorizedException2("Tenant identifier not found in request");
551
613
  }
552
614
  this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
553
615
  if (tenantIdentifier === "cloud") {
554
- this.logger.debug("Platform admin access detected, skipping tenant database validation");
555
- return true;
616
+ this.logger.log("Cloud platform access detected, skipping tenant context setup");
617
+ return next.handle();
556
618
  }
557
619
  const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
558
620
  if (!tenantInfo) {
559
621
  this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
560
- throw new UnauthorizedException("Invalid tenant");
622
+ throw new UnauthorizedException2("Invalid tenant");
561
623
  }
562
624
  if (tenantInfo.status !== "ACTIVE") {
563
625
  this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
564
- throw new UnauthorizedException(`Tenant is ${tenantInfo.status}`);
565
- }
566
- this.logger.debug(`Tenant validated: ${tenantInfo.subdomain} (${tenantInfo.type})`);
567
- return true;
568
- } catch (error) {
569
- if (error instanceof UnauthorizedException) {
570
- throw error;
571
- }
572
- this.logger.error("Unexpected error in auth guard", error);
573
- throw new UnauthorizedException("Authentication failed");
574
- }
575
- }
576
- /**
577
- * Validate access token with proper expiry checks
578
- * Throws UnauthorizedException if token is invalid or expired
579
- */
580
- validateAccessToken(token) {
581
- try {
582
- const decoded = this.jwtService.verify(token);
583
- this.logger.debug(`Access token decoded for user: ${decoded.userId}`);
584
- if (decoded.exp) {
585
- const expiryTime = decoded.exp * 1e3;
586
- const currentTime = Date.now();
587
- const timeRemaining = expiryTime - currentTime;
588
- this.logger.debug(`Access token valid for ${Math.floor(timeRemaining / 1e3)} more seconds`);
626
+ throw new UnauthorizedException2(`Tenant is ${tenantInfo.status}`);
589
627
  }
590
- return decoded;
628
+ this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
629
+ this.tenantContext.setTenant(tenantInfo);
630
+ request.tenant = tenantInfo;
631
+ this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
591
632
  } catch (error) {
592
- if (error instanceof UnauthorizedException) {
593
- throw error;
594
- }
595
- const jwtError = error;
596
- if (jwtError?.name === "TokenExpiredError") {
597
- this.logger.warn(`Access token expired at: ${jwtError?.expiredAt}`);
598
- throw new UnauthorizedException("Access token has expired");
599
- }
600
- if (jwtError?.name === "JsonWebTokenError") {
601
- this.logger.warn(`Access token verification failed: ${jwtError?.message}`);
602
- throw new UnauthorizedException("Invalid access token");
603
- }
604
- if (jwtError?.name === "NotBeforeError") {
605
- this.logger.warn("Access token used before valid (nbf claim)");
606
- throw new UnauthorizedException("Access token not yet valid");
607
- }
608
- this.logger.error("Unexpected error validating access token", error);
609
- throw new UnauthorizedException("Access token validation failed");
610
- }
611
- }
612
- /**
613
- * Validate that the access token is bound to the refresh token in the cookie.
614
- * This prevents token theft - a stolen access token is useless without the
615
- * corresponding refresh token cookie.
616
- *
617
- * @param context - The execution context containing the request
618
- * @param validatedToken - The decoded and validated JWT token
619
- * @throws UnauthorizedException if token binding validation fails
620
- */
621
- validateRefreshTokenBinding(context, validatedToken) {
622
- const config = getConfig();
623
- if (!config.jwt.validateTokenBinding) {
624
- this.logger.debug("Token binding validation is disabled");
625
- return;
626
- }
627
- if (!validatedToken.refreshTokenHash) {
628
- this.logger.debug("Token does not contain refreshTokenHash, skipping binding validation");
629
- return;
630
- }
631
- const request = context.switchToHttp().getRequest();
632
- const cookies = request.cookies || {};
633
- const refreshToken = cookies[config.cookie.refreshCookieName];
634
- if (!refreshToken) {
635
- this.logger.warn("Session validation failed - refresh token cookie not found");
636
- throw new UnauthorizedException("Session validation failed");
637
- }
638
- if (!verifyTokenHash(refreshToken, validatedToken.refreshTokenHash)) {
639
- this.logger.warn("Session validation failed - token binding mismatch");
640
- throw new UnauthorizedException("Session validation failed");
633
+ this.logger.error("Failed to set tenant context", error);
634
+ throw error;
641
635
  }
642
- this.logger.debug("Token binding validated successfully");
636
+ return next.handle();
643
637
  }
644
638
  };
645
- VrittiAuthGuard = _ts_decorate4([
646
- Injectable3({
647
- scope: Scope2.REQUEST
639
+ TenantContextInterceptor = _ts_decorate6([
640
+ Injectable4({
641
+ scope: Scope4.REQUEST
648
642
  }),
649
- _ts_metadata3("design:type", Function),
650
- _ts_metadata3("design:paramtypes", [
643
+ _ts_metadata4("design:type", Function),
644
+ _ts_metadata4("design:paramtypes", [
651
645
  typeof Reflector === "undefined" ? Object : Reflector,
652
- typeof ConfigService === "undefined" ? Object : ConfigService,
653
- typeof JwtService === "undefined" ? Object : JwtService,
646
+ typeof TenantContextService === "undefined" ? Object : TenantContextService,
654
647
  typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
655
648
  typeof RequestService === "undefined" ? Object : RequestService
656
649
  ])
657
- ], VrittiAuthGuard);
650
+ ], TenantContextInterceptor);
658
651
 
659
- // src/auth/auth-config.module.ts
660
- function _ts_decorate5(decorators, target, key, desc) {
652
+ // src/database/services/primary-database.service.ts
653
+ import { Inject as Inject2, Injectable as Injectable5, InternalServerErrorException, Logger as Logger5 } from "@nestjs/common";
654
+ import { eq, or } from "drizzle-orm";
655
+ import { drizzle } from "drizzle-orm/node-postgres";
656
+ import { Pool } from "pg";
657
+ function _ts_decorate7(decorators, target, key, desc) {
661
658
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
662
659
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
663
660
  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;
664
661
  return c > 3 && r && Object.defineProperty(target, key, r), r;
665
662
  }
666
- __name(_ts_decorate5, "_ts_decorate");
667
- var AuthConfigModule = class _AuthConfigModule {
663
+ __name(_ts_decorate7, "_ts_decorate");
664
+ function _ts_metadata5(k, v) {
665
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
666
+ }
667
+ __name(_ts_metadata5, "_ts_metadata");
668
+ function _ts_param2(paramIndex, decorator) {
669
+ return function(target, key) {
670
+ decorator(target, key, paramIndex);
671
+ };
672
+ }
673
+ __name(_ts_param2, "_ts_param");
674
+ var PrimaryDatabaseService2 = class _PrimaryDatabaseService {
668
675
  static {
669
- __name(this, "AuthConfigModule");
676
+ __name(this, "PrimaryDatabaseService");
677
+ }
678
+ options;
679
+ logger = new Logger5(_PrimaryDatabaseService.name);
680
+ /** PostgreSQL connection pool */
681
+ pool = null;
682
+ /** Drizzle database instance */
683
+ db = null;
684
+ /** In-memory cache: Map<tenantIdentifier, TenantConfig> */
685
+ tenantConfigCache = /* @__PURE__ */ new Map();
686
+ /** Cache TTL in milliseconds */
687
+ cacheTTL;
688
+ constructor(options) {
689
+ this.options = options;
690
+ this.cacheTTL = options.connectionCacheTTL || 3e5;
691
+ }
692
+ async onModuleInit() {
693
+ if (this.options.primaryDb) {
694
+ await this.initializeDrizzleClient();
695
+ }
670
696
  }
671
697
  /**
672
- * Register the auth module with async configuration
698
+ * Initialize connection to primary database using Drizzle
699
+ */
700
+ async initializeDrizzleClient() {
701
+ try {
702
+ const databaseUrl = this.buildPrimaryDbUrl();
703
+ this.pool = new Pool({
704
+ connectionString: databaseUrl,
705
+ max: this.options.maxConnections || 10
706
+ });
707
+ this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
708
+ this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
709
+ this.db = drizzle({
710
+ client: this.pool,
711
+ schema: this.options.drizzleSchema,
712
+ relations: this.options.drizzleRelations
713
+ });
714
+ this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
715
+ await this.pool.query("SELECT 1");
716
+ this.logger.log("Connected to primary database (tenant registry)");
717
+ } catch (error) {
718
+ this.logger.error("Failed to connect to primary database", error);
719
+ throw new InternalServerErrorException("Failed to initialize tenant registry");
720
+ }
721
+ }
722
+ /**
723
+ * Build connection URL from primary database properties
724
+ */
725
+ buildPrimaryDbUrl() {
726
+ if (!this.options.primaryDb) {
727
+ throw new Error("Primary database configuration not provided");
728
+ }
729
+ const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
730
+ let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
731
+ const params = new URLSearchParams();
732
+ if (schema) {
733
+ params.set("schema", schema);
734
+ }
735
+ params.set("sslmode", sslMode);
736
+ const queryString = params.toString();
737
+ if (queryString) {
738
+ url += `?${queryString}`;
739
+ }
740
+ this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
741
+ return url;
742
+ }
743
+ /**
744
+ * Mask password in connection URL for logging
745
+ */
746
+ maskPassword(url) {
747
+ return url.replace(/:([^@]+)@/, ":****@");
748
+ }
749
+ /**
750
+ * Get tenant configuration by identifier (ID or subdomain)
673
751
  *
674
- * This method:
675
- * 1. Configures JwtModule with JWT_SECRET from ConfigService
676
- * 2. Provides VrittiAuthGuard globally (applies to all routes)
677
- * 3. Exports JwtModule for use in other modules (e.g., for signing tokens)
752
+ * @param tenantIdentifier Tenant ID or subdomain
753
+ * @returns Tenant configuration or null if not found
754
+ */
755
+ async getTenantInfo(tenantIdentifier) {
756
+ const cached = this.tenantConfigCache.get(tenantIdentifier);
757
+ if (cached) {
758
+ this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
759
+ return cached;
760
+ }
761
+ try {
762
+ if (!this.db) {
763
+ throw new Error("Primary database client not initialized");
764
+ }
765
+ this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
766
+ const schema = this.options.drizzleSchema;
767
+ const { tenants, tenantDatabaseConfigs } = schema;
768
+ const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, eq(tenants.id, tenantDatabaseConfigs.tenantId)).where(or(eq(tenants.id, tenantIdentifier), eq(tenants.subdomain, tenantIdentifier))).limit(1);
769
+ if (!result.length) {
770
+ this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
771
+ return null;
772
+ }
773
+ const row = result[0];
774
+ const tenant = row.tenants;
775
+ const config = row.tenant_database_configs;
776
+ if (tenant.status !== "ACTIVE") {
777
+ this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
778
+ return null;
779
+ }
780
+ const info = {
781
+ id: tenant.id,
782
+ subdomain: tenant.subdomain,
783
+ type: tenant.dbType,
784
+ status: tenant.status,
785
+ // For SHARED tenants: schema name
786
+ schemaName: config?.dbSchema || void 0,
787
+ // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
788
+ databaseName: config?.dbName || void 0,
789
+ databaseHost: config?.dbHost || void 0,
790
+ databasePort: config?.dbPort || void 0,
791
+ databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
792
+ databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
793
+ databaseSslMode: config?.dbSslMode || void 0,
794
+ connectionPoolSize: config?.connectionPoolSize || void 0
795
+ };
796
+ this.cacheInfo(info);
797
+ return info;
798
+ } catch (error) {
799
+ this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
800
+ throw new InternalServerErrorException("Failed to resolve tenant");
801
+ }
802
+ }
803
+ /**
804
+ * Cache tenant information with TTL
805
+ */
806
+ cacheInfo(info) {
807
+ this.tenantConfigCache.set(info.id, info);
808
+ this.tenantConfigCache.set(info.subdomain, info);
809
+ setTimeout(() => {
810
+ this.tenantConfigCache.delete(info.id);
811
+ this.tenantConfigCache.delete(info.subdomain);
812
+ this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
813
+ }, this.cacheTTL);
814
+ }
815
+ /**
816
+ * Clear cached tenant information
678
817
  *
679
- * @returns Dynamic module configuration
818
+ * Useful when tenant settings are updated and cache needs to be invalidated
819
+ *
820
+ * @param tenantIdentifier Tenant ID or subdomain
680
821
  */
681
- static forRootAsync() {
682
- return {
683
- module: _AuthConfigModule,
684
- imports: [
685
- ConfigModule,
686
- RequestModule,
687
- JwtModule.registerAsync({
688
- imports: [
689
- ConfigModule
690
- ],
691
- inject: [
692
- ConfigService2
693
- ],
694
- useFactory: /* @__PURE__ */ __name((config) => ({
695
- secret: config.get("JWT_SECRET"),
696
- signOptions: {
697
- algorithm: "HS256"
698
- }
699
- }), "useFactory")
700
- })
701
- ],
702
- providers: [
703
- {
704
- provide: APP_GUARD,
705
- useClass: VrittiAuthGuard
706
- }
707
- ],
708
- exports: [
709
- JwtModule
710
- ]
711
- };
822
+ clearTenantCache(tenantIdentifier) {
823
+ const config = this.tenantConfigCache.get(tenantIdentifier);
824
+ if (config) {
825
+ this.tenantConfigCache.delete(config.id);
826
+ this.tenantConfigCache.delete(config.subdomain);
827
+ this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
828
+ }
829
+ }
830
+ /**
831
+ * Clear all cached tenant configurations
832
+ */
833
+ clearAllCaches() {
834
+ const size = this.tenantConfigCache.size;
835
+ this.tenantConfigCache.clear();
836
+ this.logger.log(`Cleared ${size} cached tenant configs`);
837
+ }
838
+ /**
839
+ * Get the Drizzle database instance for the primary database.
840
+ * This is a synchronous property that returns the initialized Drizzle client.
841
+ *
842
+ * @returns Primary database Drizzle instance
843
+ * @throws Error if primary database client is not initialized
844
+ */
845
+ get drizzleClient() {
846
+ if (!this.db) {
847
+ throw new Error("Primary database client not initialized");
848
+ }
849
+ return this.db;
850
+ }
851
+ /**
852
+ * Get the Drizzle schema
853
+ */
854
+ get schema() {
855
+ return this.options.drizzleSchema;
856
+ }
857
+ /**
858
+ * Decrypt database credentials
859
+ *
860
+ * Override this method to implement your encryption strategy
861
+ *
862
+ * @param encrypted Encrypted value
863
+ * @returns Decrypted value
864
+ */
865
+ decrypt(encrypted) {
866
+ return encrypted;
867
+ }
868
+ async onModuleDestroy() {
869
+ if (this.pool) {
870
+ await this.pool.end();
871
+ this.logger.log("Disconnected from primary database");
872
+ }
712
873
  }
713
874
  };
714
- AuthConfigModule = _ts_decorate5([
715
- Global2(),
716
- Module2({})
717
- ], AuthConfigModule);
718
-
719
- // src/database/database.module.ts
720
- import { Global as Global3, Module as Module3 } from "@nestjs/common";
721
- import { APP_INTERCEPTOR } from "@nestjs/core";
722
-
723
- // src/database/interceptors/message-tenant-context.interceptor.ts
724
- import { Injectable as Injectable5, Logger as Logger3, Scope as Scope4 } from "@nestjs/common";
725
- import { tap } from "rxjs/operators";
875
+ PrimaryDatabaseService2 = _ts_decorate7([
876
+ Injectable5(),
877
+ _ts_param2(0, Inject2(DATABASE_MODULE_OPTIONS)),
878
+ _ts_metadata5("design:type", Function),
879
+ _ts_metadata5("design:paramtypes", [
880
+ typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
881
+ ])
882
+ ], PrimaryDatabaseService2);
726
883
 
727
884
  // src/database/services/tenant-context.service.ts
728
- import { Injectable as Injectable4, Scope as Scope3, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
729
- function _ts_decorate6(decorators, target, key, desc) {
885
+ import { Injectable as Injectable6, Scope as Scope5, UnauthorizedException as UnauthorizedException3 } from "@nestjs/common";
886
+ function _ts_decorate8(decorators, target, key, desc) {
730
887
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
731
888
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
732
889
  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;
733
890
  return c > 3 && r && Object.defineProperty(target, key, r), r;
734
891
  }
735
- __name(_ts_decorate6, "_ts_decorate");
736
- var TenantContextService = class {
892
+ __name(_ts_decorate8, "_ts_decorate");
893
+ var TenantContextService2 = class {
737
894
  static {
738
895
  __name(this, "TenantContextService");
739
896
  }
@@ -763,7 +920,7 @@ var TenantContextService = class {
763
920
  */
764
921
  getTenant() {
765
922
  if (!this.tenantInfo) {
766
- throw new UnauthorizedException2("Tenant context not set");
923
+ throw new UnauthorizedException3("Tenant context not set");
767
924
  }
768
925
  return this.tenantInfo;
769
926
  }
@@ -804,195 +961,40 @@ var TenantContextService = class {
804
961
  return this.tenantInfo?.subdomain ?? null;
805
962
  }
806
963
  };
807
- TenantContextService = _ts_decorate6([
808
- Injectable4({
809
- scope: Scope3.REQUEST
964
+ TenantContextService2 = _ts_decorate8([
965
+ Injectable6({
966
+ scope: Scope5.REQUEST
810
967
  })
811
- ], TenantContextService);
968
+ ], TenantContextService2);
812
969
 
813
- // src/database/interceptors/message-tenant-context.interceptor.ts
814
- function _ts_decorate7(decorators, target, key, desc) {
970
+ // src/database/services/tenant-database.service.ts
971
+ import { Inject as Inject3, Injectable as Injectable7, InternalServerErrorException as InternalServerErrorException2, Logger as Logger6 } from "@nestjs/common";
972
+ import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
973
+ import { Pool as Pool2 } from "pg";
974
+ function _ts_decorate9(decorators, target, key, desc) {
815
975
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
816
976
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
817
977
  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;
818
978
  return c > 3 && r && Object.defineProperty(target, key, r), r;
819
979
  }
820
- __name(_ts_decorate7, "_ts_decorate");
821
- function _ts_metadata4(k, v) {
980
+ __name(_ts_decorate9, "_ts_decorate");
981
+ function _ts_metadata6(k, v) {
822
982
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
823
983
  }
824
- __name(_ts_metadata4, "_ts_metadata");
825
- var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
984
+ __name(_ts_metadata6, "_ts_metadata");
985
+ function _ts_param3(paramIndex, decorator) {
986
+ return function(target, key) {
987
+ decorator(target, key, paramIndex);
988
+ };
989
+ }
990
+ __name(_ts_param3, "_ts_param");
991
+ var TenantDatabaseService = class _TenantDatabaseService {
826
992
  static {
827
- __name(this, "MessageTenantContextInterceptor");
993
+ __name(this, "TenantDatabaseService");
828
994
  }
995
+ options;
829
996
  tenantContext;
830
- logger = new Logger3(_MessageTenantContextInterceptor.name);
831
- constructor(tenantContext) {
832
- this.tenantContext = tenantContext;
833
- }
834
- intercept(context, next) {
835
- const contextType = context.getType();
836
- if (contextType === "rpc") {
837
- const rpcContext = context.switchToRpc();
838
- const payload = rpcContext.getData();
839
- if (payload && payload.tenant) {
840
- const tenant = payload.tenant;
841
- this.logger.debug(`Setting tenant context from message: ${tenant.subdomain}`);
842
- try {
843
- this.tenantContext.setTenant(tenant);
844
- this.logger.log(`Tenant context set: ${tenant.subdomain} (${tenant.type})`);
845
- } catch (error) {
846
- this.logger.error("Failed to set tenant context from message", error);
847
- }
848
- } else {
849
- this.logger.warn("Message payload missing tenant information");
850
- }
851
- }
852
- return next.handle().pipe(tap({
853
- next: /* @__PURE__ */ __name(() => {
854
- this.cleanupContext();
855
- }, "next"),
856
- error: /* @__PURE__ */ __name(() => {
857
- this.cleanupContext();
858
- }, "error"),
859
- complete: /* @__PURE__ */ __name(() => {
860
- this.cleanupContext();
861
- }, "complete")
862
- }));
863
- }
864
- /**
865
- * Clean up tenant context after message is processed
866
- */
867
- cleanupContext() {
868
- if (this.tenantContext.hasTenant()) {
869
- const tenant = this.tenantContext.getTenantIdSafe();
870
- this.tenantContext.clearTenant();
871
- this.logger.debug(`Cleaned up tenant context: ${tenant}`);
872
- }
873
- }
874
- };
875
- MessageTenantContextInterceptor = _ts_decorate7([
876
- Injectable5({
877
- scope: Scope4.REQUEST
878
- }),
879
- _ts_metadata4("design:type", Function),
880
- _ts_metadata4("design:paramtypes", [
881
- typeof TenantContextService === "undefined" ? Object : TenantContextService
882
- ])
883
- ], MessageTenantContextInterceptor);
884
-
885
- // src/database/interceptors/tenant-context.interceptor.ts
886
- import { Injectable as Injectable6, Logger as Logger4, Scope as Scope5, UnauthorizedException as UnauthorizedException3 } from "@nestjs/common";
887
- import { Reflector as Reflector2 } from "@nestjs/core";
888
- function _ts_decorate8(decorators, target, key, desc) {
889
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
890
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
891
- 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;
892
- return c > 3 && r && Object.defineProperty(target, key, r), r;
893
- }
894
- __name(_ts_decorate8, "_ts_decorate");
895
- function _ts_metadata5(k, v) {
896
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
897
- }
898
- __name(_ts_metadata5, "_ts_metadata");
899
- var TenantContextInterceptor = class _TenantContextInterceptor {
900
- static {
901
- __name(this, "TenantContextInterceptor");
902
- }
903
- reflector;
904
- tenantContext;
905
- primaryDatabase;
906
- requestService;
907
- logger = new Logger4(_TenantContextInterceptor.name);
908
- constructor(reflector, tenantContext, primaryDatabase, requestService) {
909
- this.reflector = reflector;
910
- this.tenantContext = tenantContext;
911
- this.primaryDatabase = primaryDatabase;
912
- this.requestService = requestService;
913
- }
914
- async intercept(context, next) {
915
- const request = context.switchToHttp().getRequest();
916
- this.logger.debug(`Processing request: ${request.method} ${request.url}`);
917
- const isPublic = this.reflector.getAllAndOverride("isPublic", [
918
- context.getHandler(),
919
- context.getClass()
920
- ]);
921
- try {
922
- const tenantIdentifier = this.requestService.getTenantIdentifier();
923
- if (isPublic && !tenantIdentifier) {
924
- this.logger.debug("Public endpoint without tenant identifier, skipping tenant context setup");
925
- return next.handle();
926
- }
927
- if (!tenantIdentifier) {
928
- throw new UnauthorizedException3("Tenant identifier not found in request");
929
- }
930
- this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
931
- if (tenantIdentifier === "cloud") {
932
- this.logger.log("Cloud platform access detected, skipping tenant context setup");
933
- return next.handle();
934
- }
935
- const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
936
- if (!tenantInfo) {
937
- this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
938
- throw new UnauthorizedException3("Invalid tenant");
939
- }
940
- if (tenantInfo.status !== "ACTIVE") {
941
- this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
942
- throw new UnauthorizedException3(`Tenant is ${tenantInfo.status}`);
943
- }
944
- this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
945
- this.tenantContext.setTenant(tenantInfo);
946
- request.tenant = tenantInfo;
947
- this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
948
- } catch (error) {
949
- this.logger.error("Failed to set tenant context", error);
950
- throw error;
951
- }
952
- return next.handle();
953
- }
954
- };
955
- TenantContextInterceptor = _ts_decorate8([
956
- Injectable6({
957
- scope: Scope5.REQUEST
958
- }),
959
- _ts_metadata5("design:type", Function),
960
- _ts_metadata5("design:paramtypes", [
961
- typeof Reflector2 === "undefined" ? Object : Reflector2,
962
- typeof TenantContextService === "undefined" ? Object : TenantContextService,
963
- typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
964
- typeof RequestService === "undefined" ? Object : RequestService
965
- ])
966
- ], TenantContextInterceptor);
967
-
968
- // src/database/services/tenant-database.service.ts
969
- import { Inject as Inject3, Injectable as Injectable7, InternalServerErrorException as InternalServerErrorException2, Logger as Logger5 } from "@nestjs/common";
970
- import { Pool as Pool2 } from "pg";
971
- import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
972
- function _ts_decorate9(decorators, target, key, desc) {
973
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
974
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
975
- 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;
976
- return c > 3 && r && Object.defineProperty(target, key, r), r;
977
- }
978
- __name(_ts_decorate9, "_ts_decorate");
979
- function _ts_metadata6(k, v) {
980
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
981
- }
982
- __name(_ts_metadata6, "_ts_metadata");
983
- function _ts_param3(paramIndex, decorator) {
984
- return function(target, key) {
985
- decorator(target, key, paramIndex);
986
- };
987
- }
988
- __name(_ts_param3, "_ts_param");
989
- var TenantDatabaseService = class _TenantDatabaseService {
990
- static {
991
- __name(this, "TenantDatabaseService");
992
- }
993
- options;
994
- tenantContext;
995
- logger = new Logger5(_TenantDatabaseService.name);
997
+ logger = new Logger6(_TenantDatabaseService.name);
996
998
  /** Connection pool: Map<cacheKey, TenantConnection> */
997
999
  clients = /* @__PURE__ */ new Map();
998
1000
  /** Track last usage time for idle connection cleanup */
@@ -1211,7 +1213,7 @@ var DatabaseModule = class _DatabaseModule {
1211
1213
  * })
1212
1214
  */
1213
1215
  static forServer(options) {
1214
- return this.createDynamicModule(options, "server");
1216
+ return _DatabaseModule.createDynamicModule(options, "server");
1215
1217
  }
1216
1218
  /**
1217
1219
  * Configure DatabaseModule for Microservice/Messaging mode (RabbitMQ workers)
@@ -1233,7 +1235,7 @@ var DatabaseModule = class _DatabaseModule {
1233
1235
  * })
1234
1236
  */
1235
1237
  static forMicroservice(options) {
1236
- return this.createDynamicModule(options, "microservice");
1238
+ return _DatabaseModule.createDynamicModule(options, "microservice");
1237
1239
  }
1238
1240
  /**
1239
1241
  * Internal helper to create dynamic module with conditional interceptor registration
@@ -1250,8 +1252,8 @@ var DatabaseModule = class _DatabaseModule {
1250
1252
  };
1251
1253
  const providers = [
1252
1254
  asyncProvider,
1253
- TenantContextService,
1254
- PrimaryDatabaseService,
1255
+ TenantContextService2,
1256
+ PrimaryDatabaseService2,
1255
1257
  TenantDatabaseService
1256
1258
  ];
1257
1259
  if (mode === "server") {
@@ -1273,8 +1275,8 @@ var DatabaseModule = class _DatabaseModule {
1273
1275
  providers,
1274
1276
  exports: [
1275
1277
  TenantDatabaseService,
1276
- TenantContextService,
1277
- PrimaryDatabaseService,
1278
+ TenantContextService2,
1279
+ PrimaryDatabaseService2,
1278
1280
  asyncProvider
1279
1281
  ]
1280
1282
  };
@@ -1285,9 +1287,20 @@ DatabaseModule = _ts_decorate10([
1285
1287
  Module3({})
1286
1288
  ], DatabaseModule);
1287
1289
 
1290
+ // src/database/decorators/tenant.decorator.ts
1291
+ import { createParamDecorator } from "@nestjs/common";
1292
+ var Tenant = createParamDecorator((_data, ctx) => {
1293
+ const request = ctx.switchToHttp().getRequest();
1294
+ const tenantContext = request.app?.get?.(TenantContextService2);
1295
+ if (!tenantContext) {
1296
+ throw new Error("TenantContextService not found.");
1297
+ }
1298
+ return tenantContext.getTenant();
1299
+ });
1300
+
1288
1301
  // src/database/repositories/primary-base.repository.ts
1289
- import { Logger as Logger6 } from "@nestjs/common";
1290
- import { eq as eq2, sql, getTableName } from "drizzle-orm";
1302
+ import { Logger as Logger7 } from "@nestjs/common";
1303
+ import { eq as eq2, getTableName, sql } from "drizzle-orm";
1291
1304
  function snakeToCamel(str) {
1292
1305
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
1293
1306
  }
@@ -1357,7 +1370,7 @@ var PrimaryBaseRepository = class {
1357
1370
  this.table = table;
1358
1371
  const dbTableName = getTableName(table);
1359
1372
  this.tableName = snakeToCamel(dbTableName);
1360
- this.logger = new Logger6(this.constructor.name);
1373
+ this.logger = new Logger7(this.constructor.name);
1361
1374
  this.logger.debug(`Initialized ${this.constructor.name}`);
1362
1375
  this.logger.debug(`Table name: '${dbTableName}' -> query key: '${this.tableName}'`);
1363
1376
  }
@@ -1597,8 +1610,8 @@ var PrimaryBaseRepository = class {
1597
1610
  };
1598
1611
 
1599
1612
  // src/database/repositories/tenant-base.repository.ts
1600
- import { Logger as Logger7 } from "@nestjs/common";
1601
- import { eq as eq3, sql as sql2, getTableName as getTableName2 } from "drizzle-orm";
1613
+ import { Logger as Logger8 } from "@nestjs/common";
1614
+ import { eq as eq3, getTableName as getTableName2, sql as sql2 } from "drizzle-orm";
1602
1615
  var TenantBaseRepository = class {
1603
1616
  static {
1604
1617
  __name(this, "TenantBaseRepository");
@@ -1654,7 +1667,7 @@ var TenantBaseRepository = class {
1654
1667
  this.database = database;
1655
1668
  this.table = table;
1656
1669
  this.tableName = getTableName2(table);
1657
- this.logger = new Logger7(this.constructor.name);
1670
+ this.logger = new Logger8(this.constructor.name);
1658
1671
  this.logger.debug(`Initialized ${this.constructor.name}`);
1659
1672
  }
1660
1673
  /**
@@ -1886,262 +1899,74 @@ var TenantBaseRepository = class {
1886
1899
  }
1887
1900
  };
1888
1901
 
1889
- // src/database/decorators/tenant.decorator.ts
1890
- import { createParamDecorator } from "@nestjs/common";
1891
- var Tenant = createParamDecorator((data, ctx) => {
1892
- const request = ctx.switchToHttp().getRequest();
1893
- const tenantContext = request.app?.get?.(TenantContextService);
1894
- if (!tenantContext) {
1895
- throw new Error("TenantContextService not found.");
1896
- }
1897
- return tenantContext.getTenant();
1898
- });
1899
-
1900
- // src/auth/decorators/onboarding.decorator.ts
1901
- import { SetMetadata } from "@nestjs/common";
1902
- var Onboarding = /* @__PURE__ */ __name(() => SetMetadata("isOnboarding", true), "Onboarding");
1903
-
1904
- // src/auth/decorators/public.decorator.ts
1905
- import { SetMetadata as SetMetadata2 } from "@nestjs/common";
1906
- var Public = /* @__PURE__ */ __name(() => SetMetadata2("isPublic", true), "Public");
1902
+ // src/exceptions/bad-gateway.exception.ts
1903
+ import { HttpStatus as HttpStatus2 } from "@nestjs/common";
1907
1904
 
1908
- // src/http/http.module.ts
1909
- import { Module as Module4 } from "@nestjs/common";
1905
+ // src/exceptions/base-field.exception.ts
1906
+ import { HttpException, HttpStatus } from "@nestjs/common";
1907
+ var BaseFieldException = class extends HttpException {
1908
+ static {
1909
+ __name(this, "BaseFieldException");
1910
+ }
1911
+ constructor(statusOrMessageOrErrors, messageOrStatus, statusOrDetail, detail) {
1912
+ let errors;
1913
+ let httpStatus;
1914
+ let finalDetail;
1915
+ if (Array.isArray(statusOrMessageOrErrors)) {
1916
+ errors = statusOrMessageOrErrors;
1917
+ httpStatus = messageOrStatus || HttpStatus.BAD_REQUEST;
1918
+ finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
1919
+ } else if (typeof statusOrMessageOrErrors === "string" && typeof messageOrStatus === "string") {
1920
+ errors = [
1921
+ {
1922
+ field: statusOrMessageOrErrors,
1923
+ message: messageOrStatus
1924
+ }
1925
+ ];
1926
+ httpStatus = statusOrDetail;
1927
+ finalDetail = detail;
1928
+ } else if (typeof statusOrMessageOrErrors === "string") {
1929
+ errors = [
1930
+ {
1931
+ message: statusOrMessageOrErrors
1932
+ }
1933
+ ];
1934
+ httpStatus = messageOrStatus;
1935
+ finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
1936
+ } else {
1937
+ errors = [
1938
+ {
1939
+ message: "An error occurred"
1940
+ }
1941
+ ];
1942
+ httpStatus = statusOrMessageOrErrors;
1943
+ finalDetail = void 0;
1944
+ }
1945
+ const response = finalDetail !== void 0 ? {
1946
+ errors,
1947
+ detail: finalDetail
1948
+ } : {
1949
+ errors
1950
+ };
1951
+ super(response, httpStatus);
1952
+ }
1953
+ };
1910
1954
 
1911
- // src/http/guards/csrf.guard.ts
1912
- import { ForbiddenException, Injectable as Injectable8, Logger as Logger8 } from "@nestjs/common";
1913
- import { Reflector as Reflector3 } from "@nestjs/core";
1914
- function _ts_decorate11(decorators, target, key, desc) {
1915
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1916
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1917
- 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;
1918
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1919
- }
1920
- __name(_ts_decorate11, "_ts_decorate");
1921
- function _ts_metadata7(k, v) {
1922
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1923
- }
1924
- __name(_ts_metadata7, "_ts_metadata");
1925
- var CsrfGuard = class _CsrfGuard {
1955
+ // src/exceptions/bad-gateway.exception.ts
1956
+ var BadGatewayException = class extends BaseFieldException {
1926
1957
  static {
1927
- __name(this, "CsrfGuard");
1958
+ __name(this, "BadGatewayException");
1928
1959
  }
1929
- reflector;
1930
- logger = new Logger8(_CsrfGuard.name);
1931
- constructor(reflector) {
1932
- this.reflector = reflector;
1933
- }
1934
- async canActivate(context) {
1935
- const request = context.switchToHttp().getRequest();
1936
- const reply = context.switchToHttp().getResponse();
1937
- const safeMethods = [
1938
- "GET",
1939
- "HEAD",
1940
- "OPTIONS"
1941
- ];
1942
- if (safeMethods.includes(request.method)) {
1943
- return true;
1944
- }
1945
- try {
1946
- const fastifyInstance = request.server;
1947
- if (!fastifyInstance.csrfProtection) {
1948
- this.logger.error("CSRF protection plugin not found. Ensure @fastify/csrf-protection is registered.");
1949
- throw new ForbiddenException("CSRF protection not configured");
1950
- }
1951
- await new Promise((resolve, reject) => {
1952
- fastifyInstance.csrfProtection(request, reply, (err) => {
1953
- if (err) {
1954
- reject(err);
1955
- } else {
1956
- resolve();
1957
- }
1958
- });
1959
- });
1960
- this.logger.debug(`CSRF validation successful for ${request.method} ${request.url}`);
1961
- return true;
1962
- } catch (error) {
1963
- this.logger.warn(`CSRF validation failed for ${request.method} ${request.url}: ${error instanceof Error ? error.message : "Unknown error"}`);
1964
- throw new ForbiddenException({
1965
- errors: [
1966
- {
1967
- field: "csrf",
1968
- message: "Invalid or missing CSRF token"
1969
- }
1970
- ],
1971
- message: "CSRF validation failed"
1972
- });
1973
- }
1974
- }
1975
- };
1976
- CsrfGuard = _ts_decorate11([
1977
- Injectable8(),
1978
- _ts_metadata7("design:type", Function),
1979
- _ts_metadata7("design:paramtypes", [
1980
- typeof Reflector3 === "undefined" ? Object : Reflector3
1981
- ])
1982
- ], CsrfGuard);
1983
-
1984
- // src/http/http.module.ts
1985
- function _ts_decorate12(decorators, target, key, desc) {
1986
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1987
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1988
- 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;
1989
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1990
- }
1991
- __name(_ts_decorate12, "_ts_decorate");
1992
- var HttpModule = class {
1993
- static {
1994
- __name(this, "HttpModule");
1995
- }
1996
- };
1997
- HttpModule = _ts_decorate12([
1998
- Module4({
1999
- providers: [
2000
- CsrfGuard
2001
- ],
2002
- exports: [
2003
- CsrfGuard
2004
- ]
2005
- })
2006
- ], HttpModule);
2007
-
2008
- // src/filters/http-exception.filter.ts
2009
- import { Catch, HttpException, HttpStatus, Logger as Logger9 } from "@nestjs/common";
2010
- function _ts_decorate13(decorators, target, key, desc) {
2011
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2012
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2013
- 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;
2014
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2015
- }
2016
- __name(_ts_decorate13, "_ts_decorate");
2017
- function getHttpStatusTitle(status) {
2018
- const enumKey = Object.entries(HttpStatus).find(([key, value]) => value === status && isNaN(Number(key)))?.[0];
2019
- if (!enumKey) {
2020
- return "Error";
2021
- }
2022
- return enumKey.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
2023
- }
2024
- __name(getHttpStatusTitle, "getHttpStatusTitle");
2025
- var HttpExceptionFilter = class _HttpExceptionFilter {
2026
- static {
2027
- __name(this, "HttpExceptionFilter");
2028
- }
2029
- logger = new Logger9(_HttpExceptionFilter.name);
2030
- catch(exception, host) {
2031
- const ctx = host.switchToHttp();
2032
- const response = ctx.getResponse();
2033
- let status = HttpStatus.INTERNAL_SERVER_ERROR;
2034
- let errors = [];
2035
- let detail = "Internal server error";
2036
- if (exception instanceof HttpException) {
2037
- status = exception.getStatus();
2038
- const exceptionResponse = exception.getResponse();
2039
- if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
2040
- const responseObj = exceptionResponse;
2041
- if ("errors" in responseObj && Array.isArray(responseObj.errors)) {
2042
- errors = responseObj.errors;
2043
- detail = ("detail" in responseObj ? responseObj.detail : void 0) || exception.message;
2044
- } else if ("message" in responseObj && Array.isArray(responseObj.message)) {
2045
- errors = responseObj.message.map((msg) => {
2046
- if (typeof msg === "object" && "property" in msg && "constraints" in msg) {
2047
- const constraintValues = Object.values(msg.constraints);
2048
- return {
2049
- field: msg.property,
2050
- message: constraintValues[0] ?? "Validation failed"
2051
- };
2052
- }
2053
- return {
2054
- message: typeof msg === "string" ? msg : JSON.stringify(msg)
2055
- };
2056
- });
2057
- detail = "Validation failed";
2058
- } else if ("message" in responseObj) {
2059
- const message = responseObj.message;
2060
- errors = [
2061
- {
2062
- message: Array.isArray(message) ? message.join(", ") : message
2063
- }
2064
- ];
2065
- detail = ("error" in responseObj ? responseObj.error : void 0) || exception.message;
2066
- }
2067
- } else if (typeof exceptionResponse === "string") {
2068
- errors = [
2069
- {
2070
- message: exceptionResponse
2071
- }
2072
- ];
2073
- detail = exceptionResponse;
2074
- }
2075
- } else {
2076
- const errorMessage = exception instanceof Error ? exception.message : "Unknown error";
2077
- const stack = exception instanceof Error ? exception.stack : void 0;
2078
- this.logger.error(`Unexpected error: ${errorMessage}`, stack);
2079
- errors = [
2080
- {
2081
- message: "An unexpected error occurred"
2082
- }
2083
- ];
2084
- }
2085
- const problemDetails = {
2086
- title: getHttpStatusTitle(status),
2087
- status,
2088
- detail,
2089
- errors
2090
- };
2091
- response.status(status).send(problemDetails);
2092
- }
2093
- };
2094
- HttpExceptionFilter = _ts_decorate13([
2095
- Catch()
2096
- ], HttpExceptionFilter);
2097
-
2098
- // src/exceptions/base-field.exception.ts
2099
- import { HttpException as HttpException2, HttpStatus as HttpStatus2 } from "@nestjs/common";
2100
- var BaseFieldException = class extends HttpException2 {
2101
- static {
2102
- __name(this, "BaseFieldException");
2103
- }
2104
- constructor(statusOrMessageOrErrors, messageOrStatus, statusOrDetail, detail) {
2105
- let errors;
2106
- let httpStatus;
2107
- let finalDetail;
2108
- if (Array.isArray(statusOrMessageOrErrors)) {
2109
- errors = statusOrMessageOrErrors;
2110
- httpStatus = messageOrStatus || HttpStatus2.BAD_REQUEST;
2111
- finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
2112
- } else if (typeof statusOrMessageOrErrors === "string" && typeof messageOrStatus === "string") {
2113
- errors = [
2114
- {
2115
- field: statusOrMessageOrErrors,
2116
- message: messageOrStatus
2117
- }
2118
- ];
2119
- httpStatus = statusOrDetail;
2120
- finalDetail = detail;
2121
- } else if (typeof statusOrMessageOrErrors === "string") {
2122
- errors = [
2123
- {
2124
- message: statusOrMessageOrErrors
2125
- }
2126
- ];
2127
- httpStatus = messageOrStatus;
2128
- finalDetail = typeof statusOrDetail === "string" ? statusOrDetail : void 0;
2129
- } else {
2130
- errors = [
2131
- {
2132
- message: "An error occurred"
2133
- }
2134
- ];
2135
- httpStatus = statusOrMessageOrErrors;
2136
- finalDetail = void 0;
2137
- }
2138
- const response = finalDetail !== void 0 ? {
2139
- errors,
2140
- detail: finalDetail
2141
- } : {
2142
- errors
2143
- };
2144
- super(response, httpStatus);
1960
+ constructor(messageOrField, fieldMessageOrDetail, detail) {
1961
+ if (Array.isArray(messageOrField)) {
1962
+ super(messageOrField, HttpStatus2.BAD_GATEWAY, fieldMessageOrDetail);
1963
+ } else if (detail !== void 0) {
1964
+ super(messageOrField, fieldMessageOrDetail, HttpStatus2.BAD_GATEWAY, detail);
1965
+ } else if (fieldMessageOrDetail) {
1966
+ super(messageOrField, fieldMessageOrDetail, HttpStatus2.BAD_GATEWAY);
1967
+ } else {
1968
+ super(messageOrField, HttpStatus2.BAD_GATEWAY);
1969
+ }
2145
1970
  }
2146
1971
  };
2147
1972
 
@@ -2164,28 +1989,28 @@ var BadRequestException = class extends BaseFieldException {
2164
1989
  }
2165
1990
  };
2166
1991
 
2167
- // src/exceptions/unauthorized.exception.ts
1992
+ // src/exceptions/conflict.exception.ts
2168
1993
  import { HttpStatus as HttpStatus4 } from "@nestjs/common";
2169
- var UnauthorizedException4 = class extends BaseFieldException {
1994
+ var ConflictException = class extends BaseFieldException {
2170
1995
  static {
2171
- __name(this, "UnauthorizedException");
1996
+ __name(this, "ConflictException");
2172
1997
  }
2173
1998
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2174
1999
  if (Array.isArray(messageOrField)) {
2175
- super(messageOrField, HttpStatus4.UNAUTHORIZED, fieldMessageOrDetail);
2000
+ super(messageOrField, HttpStatus4.CONFLICT, fieldMessageOrDetail);
2176
2001
  } else if (detail !== void 0) {
2177
- super(messageOrField, fieldMessageOrDetail, HttpStatus4.UNAUTHORIZED, detail);
2002
+ super(messageOrField, fieldMessageOrDetail, HttpStatus4.CONFLICT, detail);
2178
2003
  } else if (fieldMessageOrDetail) {
2179
- super(messageOrField, fieldMessageOrDetail, HttpStatus4.UNAUTHORIZED);
2004
+ super(messageOrField, fieldMessageOrDetail, HttpStatus4.CONFLICT);
2180
2005
  } else {
2181
- super(messageOrField, HttpStatus4.UNAUTHORIZED);
2006
+ super(messageOrField, HttpStatus4.CONFLICT);
2182
2007
  }
2183
2008
  }
2184
2009
  };
2185
2010
 
2186
2011
  // src/exceptions/forbidden.exception.ts
2187
2012
  import { HttpStatus as HttpStatus5 } from "@nestjs/common";
2188
- var ForbiddenException2 = class extends BaseFieldException {
2013
+ var ForbiddenException = class extends BaseFieldException {
2189
2014
  static {
2190
2015
  __name(this, "ForbiddenException");
2191
2016
  }
@@ -2202,222 +2027,230 @@ var ForbiddenException2 = class extends BaseFieldException {
2202
2027
  }
2203
2028
  };
2204
2029
 
2205
- // src/exceptions/not-found.exception.ts
2030
+ // src/exceptions/gone.exception.ts
2206
2031
  import { HttpStatus as HttpStatus6 } from "@nestjs/common";
2207
- var NotFoundException = class extends BaseFieldException {
2032
+ var GoneException = class extends BaseFieldException {
2208
2033
  static {
2209
- __name(this, "NotFoundException");
2034
+ __name(this, "GoneException");
2210
2035
  }
2211
2036
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2212
2037
  if (Array.isArray(messageOrField)) {
2213
- super(messageOrField, HttpStatus6.NOT_FOUND, fieldMessageOrDetail);
2038
+ super(messageOrField, HttpStatus6.GONE, fieldMessageOrDetail);
2214
2039
  } else if (detail !== void 0) {
2215
- super(messageOrField, fieldMessageOrDetail, HttpStatus6.NOT_FOUND, detail);
2040
+ super(messageOrField, fieldMessageOrDetail, HttpStatus6.GONE, detail);
2216
2041
  } else if (fieldMessageOrDetail) {
2217
- super(messageOrField, fieldMessageOrDetail, HttpStatus6.NOT_FOUND);
2042
+ super(messageOrField, fieldMessageOrDetail, HttpStatus6.GONE);
2218
2043
  } else {
2219
- super(messageOrField, HttpStatus6.NOT_FOUND);
2044
+ super(messageOrField, HttpStatus6.GONE);
2220
2045
  }
2221
2046
  }
2222
2047
  };
2223
2048
 
2224
- // src/exceptions/conflict.exception.ts
2049
+ // src/exceptions/internal-server-error.exception.ts
2225
2050
  import { HttpStatus as HttpStatus7 } from "@nestjs/common";
2226
- var ConflictException = class extends BaseFieldException {
2051
+ var InternalServerErrorException3 = class extends BaseFieldException {
2227
2052
  static {
2228
- __name(this, "ConflictException");
2053
+ __name(this, "InternalServerErrorException");
2229
2054
  }
2230
2055
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2231
2056
  if (Array.isArray(messageOrField)) {
2232
- super(messageOrField, HttpStatus7.CONFLICT, fieldMessageOrDetail);
2057
+ super(messageOrField, HttpStatus7.INTERNAL_SERVER_ERROR, fieldMessageOrDetail);
2233
2058
  } else if (detail !== void 0) {
2234
- super(messageOrField, fieldMessageOrDetail, HttpStatus7.CONFLICT, detail);
2059
+ super(messageOrField, fieldMessageOrDetail, HttpStatus7.INTERNAL_SERVER_ERROR, detail);
2235
2060
  } else if (fieldMessageOrDetail) {
2236
- super(messageOrField, fieldMessageOrDetail, HttpStatus7.CONFLICT);
2061
+ super(messageOrField, fieldMessageOrDetail, HttpStatus7.INTERNAL_SERVER_ERROR);
2237
2062
  } else {
2238
- super(messageOrField, HttpStatus7.CONFLICT);
2063
+ super(messageOrField, HttpStatus7.INTERNAL_SERVER_ERROR);
2239
2064
  }
2240
2065
  }
2241
2066
  };
2242
2067
 
2243
- // src/exceptions/internal-server-error.exception.ts
2068
+ // src/exceptions/method-not-allowed.exception.ts
2244
2069
  import { HttpStatus as HttpStatus8 } from "@nestjs/common";
2245
- var InternalServerErrorException3 = class extends BaseFieldException {
2070
+ var MethodNotAllowedException = class extends BaseFieldException {
2246
2071
  static {
2247
- __name(this, "InternalServerErrorException");
2072
+ __name(this, "MethodNotAllowedException");
2248
2073
  }
2249
2074
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2250
2075
  if (Array.isArray(messageOrField)) {
2251
- super(messageOrField, HttpStatus8.INTERNAL_SERVER_ERROR, fieldMessageOrDetail);
2076
+ super(messageOrField, HttpStatus8.METHOD_NOT_ALLOWED, fieldMessageOrDetail);
2252
2077
  } else if (detail !== void 0) {
2253
- super(messageOrField, fieldMessageOrDetail, HttpStatus8.INTERNAL_SERVER_ERROR, detail);
2078
+ super(messageOrField, fieldMessageOrDetail, HttpStatus8.METHOD_NOT_ALLOWED, detail);
2254
2079
  } else if (fieldMessageOrDetail) {
2255
- super(messageOrField, fieldMessageOrDetail, HttpStatus8.INTERNAL_SERVER_ERROR);
2080
+ super(messageOrField, fieldMessageOrDetail, HttpStatus8.METHOD_NOT_ALLOWED);
2256
2081
  } else {
2257
- super(messageOrField, HttpStatus8.INTERNAL_SERVER_ERROR);
2082
+ super(messageOrField, HttpStatus8.METHOD_NOT_ALLOWED);
2258
2083
  }
2259
2084
  }
2260
2085
  };
2261
2086
 
2262
- // src/exceptions/validation.exception.ts
2087
+ // src/exceptions/not-acceptable.exception.ts
2263
2088
  import { HttpStatus as HttpStatus9 } from "@nestjs/common";
2264
- var ValidationException = class extends BaseFieldException {
2089
+ var NotAcceptableException = class extends BaseFieldException {
2265
2090
  static {
2266
- __name(this, "ValidationException");
2091
+ __name(this, "NotAcceptableException");
2267
2092
  }
2268
- constructor(errors, detail) {
2269
- super(errors, HttpStatus9.BAD_REQUEST, detail);
2093
+ constructor(messageOrField, fieldMessageOrDetail, detail) {
2094
+ if (Array.isArray(messageOrField)) {
2095
+ super(messageOrField, HttpStatus9.NOT_ACCEPTABLE, fieldMessageOrDetail);
2096
+ } else if (detail !== void 0) {
2097
+ super(messageOrField, fieldMessageOrDetail, HttpStatus9.NOT_ACCEPTABLE, detail);
2098
+ } else if (fieldMessageOrDetail) {
2099
+ super(messageOrField, fieldMessageOrDetail, HttpStatus9.NOT_ACCEPTABLE);
2100
+ } else {
2101
+ super(messageOrField, HttpStatus9.NOT_ACCEPTABLE);
2102
+ }
2270
2103
  }
2271
2104
  };
2272
2105
 
2273
- // src/exceptions/unprocessable-entity.exception.ts
2106
+ // src/exceptions/not-found.exception.ts
2274
2107
  import { HttpStatus as HttpStatus10 } from "@nestjs/common";
2275
- var UnprocessableEntityException = class extends BaseFieldException {
2108
+ var NotFoundException = class extends BaseFieldException {
2276
2109
  static {
2277
- __name(this, "UnprocessableEntityException");
2110
+ __name(this, "NotFoundException");
2278
2111
  }
2279
2112
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2280
2113
  if (Array.isArray(messageOrField)) {
2281
- super(messageOrField, HttpStatus10.UNPROCESSABLE_ENTITY, fieldMessageOrDetail);
2114
+ super(messageOrField, HttpStatus10.NOT_FOUND, fieldMessageOrDetail);
2282
2115
  } else if (detail !== void 0) {
2283
- super(messageOrField, fieldMessageOrDetail, HttpStatus10.UNPROCESSABLE_ENTITY, detail);
2116
+ super(messageOrField, fieldMessageOrDetail, HttpStatus10.NOT_FOUND, detail);
2284
2117
  } else if (fieldMessageOrDetail) {
2285
- super(messageOrField, fieldMessageOrDetail, HttpStatus10.UNPROCESSABLE_ENTITY);
2118
+ super(messageOrField, fieldMessageOrDetail, HttpStatus10.NOT_FOUND);
2286
2119
  } else {
2287
- super(messageOrField, HttpStatus10.UNPROCESSABLE_ENTITY);
2120
+ super(messageOrField, HttpStatus10.NOT_FOUND);
2288
2121
  }
2289
2122
  }
2290
2123
  };
2291
2124
 
2292
- // src/exceptions/too-many-requests.exception.ts
2125
+ // src/exceptions/not-implemented.exception.ts
2293
2126
  import { HttpStatus as HttpStatus11 } from "@nestjs/common";
2294
- var TooManyRequestsException = class extends BaseFieldException {
2127
+ var NotImplementedException = class extends BaseFieldException {
2295
2128
  static {
2296
- __name(this, "TooManyRequestsException");
2129
+ __name(this, "NotImplementedException");
2297
2130
  }
2298
2131
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2299
2132
  if (Array.isArray(messageOrField)) {
2300
- super(messageOrField, HttpStatus11.TOO_MANY_REQUESTS, fieldMessageOrDetail);
2133
+ super(messageOrField, HttpStatus11.NOT_IMPLEMENTED, fieldMessageOrDetail);
2301
2134
  } else if (detail !== void 0) {
2302
- super(messageOrField, fieldMessageOrDetail, HttpStatus11.TOO_MANY_REQUESTS, detail);
2135
+ super(messageOrField, fieldMessageOrDetail, HttpStatus11.NOT_IMPLEMENTED, detail);
2303
2136
  } else if (fieldMessageOrDetail) {
2304
- super(messageOrField, fieldMessageOrDetail, HttpStatus11.TOO_MANY_REQUESTS);
2137
+ super(messageOrField, fieldMessageOrDetail, HttpStatus11.NOT_IMPLEMENTED);
2305
2138
  } else {
2306
- super(messageOrField, HttpStatus11.TOO_MANY_REQUESTS);
2139
+ super(messageOrField, HttpStatus11.NOT_IMPLEMENTED);
2307
2140
  }
2308
2141
  }
2309
2142
  };
2310
2143
 
2311
- // src/exceptions/service-unavailable.exception.ts
2144
+ // src/exceptions/payload-too-large.exception.ts
2312
2145
  import { HttpStatus as HttpStatus12 } from "@nestjs/common";
2313
- var ServiceUnavailableException = class extends BaseFieldException {
2146
+ var PayloadTooLargeException = class extends BaseFieldException {
2314
2147
  static {
2315
- __name(this, "ServiceUnavailableException");
2148
+ __name(this, "PayloadTooLargeException");
2316
2149
  }
2317
2150
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2318
2151
  if (Array.isArray(messageOrField)) {
2319
- super(messageOrField, HttpStatus12.SERVICE_UNAVAILABLE, fieldMessageOrDetail);
2152
+ super(messageOrField, HttpStatus12.PAYLOAD_TOO_LARGE, fieldMessageOrDetail);
2320
2153
  } else if (detail !== void 0) {
2321
- super(messageOrField, fieldMessageOrDetail, HttpStatus12.SERVICE_UNAVAILABLE, detail);
2154
+ super(messageOrField, fieldMessageOrDetail, HttpStatus12.PAYLOAD_TOO_LARGE, detail);
2322
2155
  } else if (fieldMessageOrDetail) {
2323
- super(messageOrField, fieldMessageOrDetail, HttpStatus12.SERVICE_UNAVAILABLE);
2156
+ super(messageOrField, fieldMessageOrDetail, HttpStatus12.PAYLOAD_TOO_LARGE);
2324
2157
  } else {
2325
- super(messageOrField, HttpStatus12.SERVICE_UNAVAILABLE);
2158
+ super(messageOrField, HttpStatus12.PAYLOAD_TOO_LARGE);
2326
2159
  }
2327
2160
  }
2328
2161
  };
2329
2162
 
2330
- // src/exceptions/method-not-allowed.exception.ts
2163
+ // src/exceptions/request-timeout.exception.ts
2331
2164
  import { HttpStatus as HttpStatus13 } from "@nestjs/common";
2332
- var MethodNotAllowedException = class extends BaseFieldException {
2165
+ var RequestTimeoutException = class extends BaseFieldException {
2333
2166
  static {
2334
- __name(this, "MethodNotAllowedException");
2167
+ __name(this, "RequestTimeoutException");
2335
2168
  }
2336
2169
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2337
2170
  if (Array.isArray(messageOrField)) {
2338
- super(messageOrField, HttpStatus13.METHOD_NOT_ALLOWED, fieldMessageOrDetail);
2171
+ super(messageOrField, HttpStatus13.REQUEST_TIMEOUT, fieldMessageOrDetail);
2339
2172
  } else if (detail !== void 0) {
2340
- super(messageOrField, fieldMessageOrDetail, HttpStatus13.METHOD_NOT_ALLOWED, detail);
2173
+ super(messageOrField, fieldMessageOrDetail, HttpStatus13.REQUEST_TIMEOUT, detail);
2341
2174
  } else if (fieldMessageOrDetail) {
2342
- super(messageOrField, fieldMessageOrDetail, HttpStatus13.METHOD_NOT_ALLOWED);
2175
+ super(messageOrField, fieldMessageOrDetail, HttpStatus13.REQUEST_TIMEOUT);
2343
2176
  } else {
2344
- super(messageOrField, HttpStatus13.METHOD_NOT_ALLOWED);
2177
+ super(messageOrField, HttpStatus13.REQUEST_TIMEOUT);
2345
2178
  }
2346
2179
  }
2347
2180
  };
2348
2181
 
2349
- // src/exceptions/gone.exception.ts
2182
+ // src/exceptions/service-unavailable.exception.ts
2350
2183
  import { HttpStatus as HttpStatus14 } from "@nestjs/common";
2351
- var GoneException = class extends BaseFieldException {
2184
+ var ServiceUnavailableException = class extends BaseFieldException {
2352
2185
  static {
2353
- __name(this, "GoneException");
2186
+ __name(this, "ServiceUnavailableException");
2354
2187
  }
2355
2188
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2356
2189
  if (Array.isArray(messageOrField)) {
2357
- super(messageOrField, HttpStatus14.GONE, fieldMessageOrDetail);
2190
+ super(messageOrField, HttpStatus14.SERVICE_UNAVAILABLE, fieldMessageOrDetail);
2358
2191
  } else if (detail !== void 0) {
2359
- super(messageOrField, fieldMessageOrDetail, HttpStatus14.GONE, detail);
2192
+ super(messageOrField, fieldMessageOrDetail, HttpStatus14.SERVICE_UNAVAILABLE, detail);
2360
2193
  } else if (fieldMessageOrDetail) {
2361
- super(messageOrField, fieldMessageOrDetail, HttpStatus14.GONE);
2194
+ super(messageOrField, fieldMessageOrDetail, HttpStatus14.SERVICE_UNAVAILABLE);
2362
2195
  } else {
2363
- super(messageOrField, HttpStatus14.GONE);
2196
+ super(messageOrField, HttpStatus14.SERVICE_UNAVAILABLE);
2364
2197
  }
2365
2198
  }
2366
2199
  };
2367
2200
 
2368
- // src/exceptions/not-acceptable.exception.ts
2201
+ // src/exceptions/too-many-requests.exception.ts
2369
2202
  import { HttpStatus as HttpStatus15 } from "@nestjs/common";
2370
- var NotAcceptableException = class extends BaseFieldException {
2203
+ var TooManyRequestsException = class extends BaseFieldException {
2371
2204
  static {
2372
- __name(this, "NotAcceptableException");
2205
+ __name(this, "TooManyRequestsException");
2373
2206
  }
2374
2207
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2375
2208
  if (Array.isArray(messageOrField)) {
2376
- super(messageOrField, HttpStatus15.NOT_ACCEPTABLE, fieldMessageOrDetail);
2209
+ super(messageOrField, HttpStatus15.TOO_MANY_REQUESTS, fieldMessageOrDetail);
2377
2210
  } else if (detail !== void 0) {
2378
- super(messageOrField, fieldMessageOrDetail, HttpStatus15.NOT_ACCEPTABLE, detail);
2211
+ super(messageOrField, fieldMessageOrDetail, HttpStatus15.TOO_MANY_REQUESTS, detail);
2379
2212
  } else if (fieldMessageOrDetail) {
2380
- super(messageOrField, fieldMessageOrDetail, HttpStatus15.NOT_ACCEPTABLE);
2213
+ super(messageOrField, fieldMessageOrDetail, HttpStatus15.TOO_MANY_REQUESTS);
2381
2214
  } else {
2382
- super(messageOrField, HttpStatus15.NOT_ACCEPTABLE);
2215
+ super(messageOrField, HttpStatus15.TOO_MANY_REQUESTS);
2383
2216
  }
2384
2217
  }
2385
2218
  };
2386
2219
 
2387
- // src/exceptions/request-timeout.exception.ts
2220
+ // src/exceptions/unauthorized.exception.ts
2388
2221
  import { HttpStatus as HttpStatus16 } from "@nestjs/common";
2389
- var RequestTimeoutException = class extends BaseFieldException {
2222
+ var UnauthorizedException4 = class extends BaseFieldException {
2390
2223
  static {
2391
- __name(this, "RequestTimeoutException");
2224
+ __name(this, "UnauthorizedException");
2392
2225
  }
2393
2226
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2394
2227
  if (Array.isArray(messageOrField)) {
2395
- super(messageOrField, HttpStatus16.REQUEST_TIMEOUT, fieldMessageOrDetail);
2228
+ super(messageOrField, HttpStatus16.UNAUTHORIZED, fieldMessageOrDetail);
2396
2229
  } else if (detail !== void 0) {
2397
- super(messageOrField, fieldMessageOrDetail, HttpStatus16.REQUEST_TIMEOUT, detail);
2230
+ super(messageOrField, fieldMessageOrDetail, HttpStatus16.UNAUTHORIZED, detail);
2398
2231
  } else if (fieldMessageOrDetail) {
2399
- super(messageOrField, fieldMessageOrDetail, HttpStatus16.REQUEST_TIMEOUT);
2232
+ super(messageOrField, fieldMessageOrDetail, HttpStatus16.UNAUTHORIZED);
2400
2233
  } else {
2401
- super(messageOrField, HttpStatus16.REQUEST_TIMEOUT);
2234
+ super(messageOrField, HttpStatus16.UNAUTHORIZED);
2402
2235
  }
2403
2236
  }
2404
2237
  };
2405
2238
 
2406
- // src/exceptions/payload-too-large.exception.ts
2239
+ // src/exceptions/unprocessable-entity.exception.ts
2407
2240
  import { HttpStatus as HttpStatus17 } from "@nestjs/common";
2408
- var PayloadTooLargeException = class extends BaseFieldException {
2241
+ var UnprocessableEntityException = class extends BaseFieldException {
2409
2242
  static {
2410
- __name(this, "PayloadTooLargeException");
2243
+ __name(this, "UnprocessableEntityException");
2411
2244
  }
2412
2245
  constructor(messageOrField, fieldMessageOrDetail, detail) {
2413
2246
  if (Array.isArray(messageOrField)) {
2414
- super(messageOrField, HttpStatus17.PAYLOAD_TOO_LARGE, fieldMessageOrDetail);
2247
+ super(messageOrField, HttpStatus17.UNPROCESSABLE_ENTITY, fieldMessageOrDetail);
2415
2248
  } else if (detail !== void 0) {
2416
- super(messageOrField, fieldMessageOrDetail, HttpStatus17.PAYLOAD_TOO_LARGE, detail);
2249
+ super(messageOrField, fieldMessageOrDetail, HttpStatus17.UNPROCESSABLE_ENTITY, detail);
2417
2250
  } else if (fieldMessageOrDetail) {
2418
- super(messageOrField, fieldMessageOrDetail, HttpStatus17.PAYLOAD_TOO_LARGE);
2251
+ super(messageOrField, fieldMessageOrDetail, HttpStatus17.UNPROCESSABLE_ENTITY);
2419
2252
  } else {
2420
- super(messageOrField, HttpStatus17.PAYLOAD_TOO_LARGE);
2253
+ super(messageOrField, HttpStatus17.UNPROCESSABLE_ENTITY);
2421
2254
  }
2422
2255
  }
2423
2256
  };
@@ -2441,103 +2274,445 @@ var UnsupportedMediaTypeException = class extends BaseFieldException {
2441
2274
  }
2442
2275
  };
2443
2276
 
2444
- // src/exceptions/not-implemented.exception.ts
2277
+ // src/exceptions/validation.exception.ts
2445
2278
  import { HttpStatus as HttpStatus19 } from "@nestjs/common";
2446
- var NotImplementedException = class extends BaseFieldException {
2279
+ var ValidationException = class extends BaseFieldException {
2447
2280
  static {
2448
- __name(this, "NotImplementedException");
2281
+ __name(this, "ValidationException");
2449
2282
  }
2450
- constructor(messageOrField, fieldMessageOrDetail, detail) {
2451
- if (Array.isArray(messageOrField)) {
2452
- super(messageOrField, HttpStatus19.NOT_IMPLEMENTED, fieldMessageOrDetail);
2453
- } else if (detail !== void 0) {
2454
- super(messageOrField, fieldMessageOrDetail, HttpStatus19.NOT_IMPLEMENTED, detail);
2455
- } else if (fieldMessageOrDetail) {
2456
- super(messageOrField, fieldMessageOrDetail, HttpStatus19.NOT_IMPLEMENTED);
2283
+ constructor(errors, detail) {
2284
+ super(errors, HttpStatus19.BAD_REQUEST, detail);
2285
+ }
2286
+ };
2287
+
2288
+ // src/filters/http-exception.filter.ts
2289
+ import { Catch, HttpException as HttpException2, HttpStatus as HttpStatus20, Logger as Logger9 } from "@nestjs/common";
2290
+ function _ts_decorate11(decorators, target, key, desc) {
2291
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2292
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2293
+ 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;
2294
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2295
+ }
2296
+ __name(_ts_decorate11, "_ts_decorate");
2297
+ function getHttpStatusTitle(status) {
2298
+ const enumKey = Object.entries(HttpStatus20).find(([key, value]) => value === status && Number.isNaN(Number(key)))?.[0];
2299
+ if (!enumKey) {
2300
+ return "Error";
2301
+ }
2302
+ return enumKey.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
2303
+ }
2304
+ __name(getHttpStatusTitle, "getHttpStatusTitle");
2305
+ var HttpExceptionFilter = class _HttpExceptionFilter {
2306
+ static {
2307
+ __name(this, "HttpExceptionFilter");
2308
+ }
2309
+ logger = new Logger9(_HttpExceptionFilter.name);
2310
+ catch(exception, host) {
2311
+ const ctx = host.switchToHttp();
2312
+ const response = ctx.getResponse();
2313
+ let status = HttpStatus20.INTERNAL_SERVER_ERROR;
2314
+ let errors = [];
2315
+ let detail = "Internal server error";
2316
+ if (exception instanceof HttpException2) {
2317
+ status = exception.getStatus();
2318
+ const exceptionResponse = exception.getResponse();
2319
+ if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
2320
+ const responseObj = exceptionResponse;
2321
+ if ("errors" in responseObj && Array.isArray(responseObj.errors)) {
2322
+ errors = responseObj.errors;
2323
+ detail = ("detail" in responseObj ? responseObj.detail : void 0) || exception.message;
2324
+ } else if ("message" in responseObj && Array.isArray(responseObj.message)) {
2325
+ errors = responseObj.message.map((msg) => {
2326
+ if (typeof msg === "object" && "property" in msg && "constraints" in msg) {
2327
+ const constraintValues = Object.values(msg.constraints);
2328
+ return {
2329
+ field: msg.property,
2330
+ message: constraintValues[0] ?? "Validation failed"
2331
+ };
2332
+ }
2333
+ return {
2334
+ message: typeof msg === "string" ? msg : JSON.stringify(msg)
2335
+ };
2336
+ });
2337
+ detail = "Validation failed";
2338
+ } else if ("message" in responseObj) {
2339
+ const message = responseObj.message;
2340
+ errors = [
2341
+ {
2342
+ message: Array.isArray(message) ? message.join(", ") : message
2343
+ }
2344
+ ];
2345
+ detail = ("error" in responseObj ? responseObj.error : void 0) || exception.message;
2346
+ }
2347
+ } else if (typeof exceptionResponse === "string") {
2348
+ errors = [
2349
+ {
2350
+ message: exceptionResponse
2351
+ }
2352
+ ];
2353
+ detail = exceptionResponse;
2354
+ }
2457
2355
  } else {
2458
- super(messageOrField, HttpStatus19.NOT_IMPLEMENTED);
2356
+ const errorMessage = exception instanceof Error ? exception.message : "Unknown error";
2357
+ const stack = exception instanceof Error ? exception.stack : void 0;
2358
+ this.logger.error(`Unexpected error: ${errorMessage}`, stack);
2359
+ errors = [
2360
+ {
2361
+ message: "An unexpected error occurred"
2362
+ }
2363
+ ];
2459
2364
  }
2365
+ const problemDetails = {
2366
+ title: getHttpStatusTitle(status),
2367
+ status,
2368
+ detail,
2369
+ errors
2370
+ };
2371
+ response.status(status).send(problemDetails);
2460
2372
  }
2461
2373
  };
2374
+ HttpExceptionFilter = _ts_decorate11([
2375
+ Catch()
2376
+ ], HttpExceptionFilter);
2462
2377
 
2463
- // src/exceptions/bad-gateway.exception.ts
2464
- import { HttpStatus as HttpStatus20 } from "@nestjs/common";
2465
- var BadGatewayException = class extends BaseFieldException {
2378
+ // src/http/guards/csrf.guard.ts
2379
+ import { ForbiddenException as ForbiddenException2, Injectable as Injectable8, Logger as Logger10 } from "@nestjs/common";
2380
+ function _ts_decorate12(decorators, target, key, desc) {
2381
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2382
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2383
+ 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;
2384
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2385
+ }
2386
+ __name(_ts_decorate12, "_ts_decorate");
2387
+ var CsrfGuard = class _CsrfGuard {
2466
2388
  static {
2467
- __name(this, "BadGatewayException");
2389
+ __name(this, "CsrfGuard");
2468
2390
  }
2469
- constructor(messageOrField, fieldMessageOrDetail, detail) {
2470
- if (Array.isArray(messageOrField)) {
2471
- super(messageOrField, HttpStatus20.BAD_GATEWAY, fieldMessageOrDetail);
2472
- } else if (detail !== void 0) {
2473
- super(messageOrField, fieldMessageOrDetail, HttpStatus20.BAD_GATEWAY, detail);
2474
- } else if (fieldMessageOrDetail) {
2475
- super(messageOrField, fieldMessageOrDetail, HttpStatus20.BAD_GATEWAY);
2476
- } else {
2477
- super(messageOrField, HttpStatus20.BAD_GATEWAY);
2391
+ logger = new Logger10(_CsrfGuard.name);
2392
+ async canActivate(context) {
2393
+ const request = context.switchToHttp().getRequest();
2394
+ const reply = context.switchToHttp().getResponse();
2395
+ const safeMethods = [
2396
+ "GET",
2397
+ "HEAD",
2398
+ "OPTIONS"
2399
+ ];
2400
+ if (safeMethods.includes(request.method)) {
2401
+ return true;
2402
+ }
2403
+ try {
2404
+ const fastifyInstance = request.server;
2405
+ if (!fastifyInstance.csrfProtection) {
2406
+ this.logger.error("CSRF protection plugin not found. Ensure @fastify/csrf-protection is registered.");
2407
+ throw new ForbiddenException2("CSRF protection not configured");
2408
+ }
2409
+ await new Promise((resolve, reject) => {
2410
+ fastifyInstance.csrfProtection(request, reply, (err) => {
2411
+ if (err) {
2412
+ reject(err);
2413
+ } else {
2414
+ resolve();
2415
+ }
2416
+ });
2417
+ });
2418
+ this.logger.debug(`CSRF validation successful for ${request.method} ${request.url}`);
2419
+ return true;
2420
+ } catch (error) {
2421
+ this.logger.warn(`CSRF validation failed for ${request.method} ${request.url}: ${error instanceof Error ? error.message : "Unknown error"}`);
2422
+ throw new ForbiddenException2({
2423
+ errors: [
2424
+ {
2425
+ field: "csrf",
2426
+ message: "Invalid or missing CSRF token"
2427
+ }
2428
+ ],
2429
+ message: "CSRF validation failed"
2430
+ });
2431
+ }
2432
+ }
2433
+ };
2434
+ CsrfGuard = _ts_decorate12([
2435
+ Injectable8()
2436
+ ], CsrfGuard);
2437
+
2438
+ // src/http/http.module.ts
2439
+ import { Module as Module4 } from "@nestjs/common";
2440
+ function _ts_decorate13(decorators, target, key, desc) {
2441
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2442
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2443
+ 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;
2444
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2445
+ }
2446
+ __name(_ts_decorate13, "_ts_decorate");
2447
+ var HttpModule = class {
2448
+ static {
2449
+ __name(this, "HttpModule");
2450
+ }
2451
+ };
2452
+ HttpModule = _ts_decorate13([
2453
+ Module4({
2454
+ providers: [
2455
+ CsrfGuard
2456
+ ],
2457
+ exports: [
2458
+ CsrfGuard
2459
+ ]
2460
+ })
2461
+ ], HttpModule);
2462
+
2463
+ // src/logger/interceptors/http-logger.interceptor.ts
2464
+ import { Injectable as Injectable9, Optional } from "@nestjs/common";
2465
+ import { catchError, tap as tap2 } from "rxjs/operators";
2466
+
2467
+ // src/logger/utils/index.ts
2468
+ import { AsyncLocalStorage } from "async_hooks";
2469
+ import { randomUUID } from "crypto";
2470
+ var correlationStorage = new AsyncLocalStorage();
2471
+ function getCorrelationContext() {
2472
+ return correlationStorage.getStore();
2473
+ }
2474
+ __name(getCorrelationContext, "getCorrelationContext");
2475
+ function runWithCorrelationContext(context, callback) {
2476
+ return correlationStorage.run(context, callback);
2477
+ }
2478
+ __name(runWithCorrelationContext, "runWithCorrelationContext");
2479
+ function updateCorrelationContext(updates) {
2480
+ const context = correlationStorage.getStore();
2481
+ if (context) {
2482
+ Object.assign(context, updates);
2483
+ }
2484
+ }
2485
+ __name(updateCorrelationContext, "updateCorrelationContext");
2486
+ var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
2487
+ function generateCorrelationId() {
2488
+ return randomUUID();
2489
+ }
2490
+ __name(generateCorrelationId, "generateCorrelationId");
2491
+ function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
2492
+ if (typeof reply.header === "function") {
2493
+ reply.header(headerName, correlationId);
2494
+ } else if (reply.raw && typeof reply.raw.setHeader === "function") {
2495
+ reply.raw.setHeader(headerName, correlationId);
2496
+ }
2497
+ }
2498
+ __name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
2499
+
2500
+ // src/logger/interceptors/http-logger.interceptor.ts
2501
+ function _ts_decorate14(decorators, target, key, desc) {
2502
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2503
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2504
+ 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;
2505
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2506
+ }
2507
+ __name(_ts_decorate14, "_ts_decorate");
2508
+ function _ts_metadata7(k, v) {
2509
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2510
+ }
2511
+ __name(_ts_metadata7, "_ts_metadata");
2512
+ function _ts_param4(paramIndex, decorator) {
2513
+ return function(target, key) {
2514
+ decorator(target, key, paramIndex);
2515
+ };
2516
+ }
2517
+ __name(_ts_param4, "_ts_param");
2518
+ var HttpLoggerInterceptor = class {
2519
+ static {
2520
+ __name(this, "HttpLoggerInterceptor");
2521
+ }
2522
+ logger;
2523
+ enableRequestLog;
2524
+ enableResponseLog;
2525
+ slowRequestThreshold;
2526
+ constructor(logger, options) {
2527
+ this.logger = logger;
2528
+ this.enableRequestLog = options?.enableRequestLog ?? true;
2529
+ this.enableResponseLog = options?.enableResponseLog ?? true;
2530
+ this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
2531
+ }
2532
+ intercept(context, next) {
2533
+ if (context.getType() !== "http") {
2534
+ return next.handle();
2535
+ }
2536
+ const httpContext = context.switchToHttp();
2537
+ const request = httpContext.getRequest();
2538
+ const response = httpContext.getResponse();
2539
+ const startTime = Date.now();
2540
+ if (this.enableRequestLog) {
2541
+ this.logRequest(request);
2542
+ }
2543
+ return next.handle().pipe(tap2(() => {
2544
+ if (this.enableResponseLog) {
2545
+ const duration = Date.now() - startTime;
2546
+ this.logResponse(request, response, duration);
2547
+ }
2548
+ }), catchError((error) => {
2549
+ const duration = Date.now() - startTime;
2550
+ this.logError(request, response, duration, error);
2551
+ throw error;
2552
+ }));
2553
+ }
2554
+ logRequest(request) {
2555
+ try {
2556
+ const correlationContext = getCorrelationContext();
2557
+ const metadata = {
2558
+ type: "http_request",
2559
+ method: request.method,
2560
+ url: request.url,
2561
+ correlationId: correlationContext?.correlationId,
2562
+ ip: request.ip,
2563
+ userAgent: request.headers["user-agent"]
2564
+ };
2565
+ this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
2566
+ } catch (error) {
2567
+ this.logger.error("Failed to log HTTP request", error.stack);
2568
+ }
2569
+ }
2570
+ logResponse(request, response, duration) {
2571
+ try {
2572
+ const correlationContext = getCorrelationContext();
2573
+ const statusCode = response.statusCode;
2574
+ const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
2575
+ const metadata = {
2576
+ type: "http_response",
2577
+ method: request.method,
2578
+ url: request.url,
2579
+ statusCode,
2580
+ duration,
2581
+ correlationId: correlationContext?.correlationId
2582
+ };
2583
+ if (duration > this.slowRequestThreshold) {
2584
+ metadata.slowRequest = true;
2585
+ }
2586
+ const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
2587
+ this.logger.logWithMetadata(logLevel, message, metadata);
2588
+ } catch (error) {
2589
+ this.logger.error("Failed to log HTTP response", error.stack);
2590
+ }
2591
+ }
2592
+ logError(request, response, duration, error) {
2593
+ try {
2594
+ const correlationContext = getCorrelationContext();
2595
+ const statusCode = response.statusCode || 500;
2596
+ const metadata = {
2597
+ type: "http_error",
2598
+ method: request.method,
2599
+ url: request.url,
2600
+ statusCode,
2601
+ duration,
2602
+ correlationId: correlationContext?.correlationId,
2603
+ errorName: error?.name || "Error",
2604
+ errorMessage: error?.message || "Unknown error"
2605
+ };
2606
+ if (error?.stack) {
2607
+ metadata.trace = error.stack;
2608
+ }
2609
+ if (error?.response) {
2610
+ metadata.errorDetails = error.response;
2611
+ }
2612
+ const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
2613
+ this.logger.logWithMetadata("error", message, metadata);
2614
+ } catch (loggingError) {
2615
+ this.logger.error("Failed to log HTTP error", loggingError.stack);
2616
+ }
2617
+ }
2618
+ };
2619
+ HttpLoggerInterceptor = _ts_decorate14([
2620
+ Injectable9(),
2621
+ _ts_param4(1, Optional()),
2622
+ _ts_metadata7("design:type", Function),
2623
+ _ts_metadata7("design:paramtypes", [
2624
+ typeof LoggerService === "undefined" ? Object : LoggerService,
2625
+ typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
2626
+ ])
2627
+ ], HttpLoggerInterceptor);
2628
+
2629
+ // src/logger/logger.module.ts
2630
+ import { Global as Global4, Logger as Logger11, Module as Module5 } from "@nestjs/common";
2631
+
2632
+ // src/logger/middleware/correlation-id.middleware.ts
2633
+ import { Injectable as Injectable10 } from "@nestjs/common";
2634
+ function _ts_decorate15(decorators, target, key, desc) {
2635
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2636
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2637
+ 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;
2638
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2639
+ }
2640
+ __name(_ts_decorate15, "_ts_decorate");
2641
+ function _ts_metadata8(k, v) {
2642
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2643
+ }
2644
+ __name(_ts_metadata8, "_ts_metadata");
2645
+ var CorrelationIdMiddleware = class {
2646
+ static {
2647
+ __name(this, "CorrelationIdMiddleware");
2648
+ }
2649
+ includeInResponse;
2650
+ responseHeader;
2651
+ constructor(options = {}) {
2652
+ this.includeInResponse = options.includeInResponse ?? true;
2653
+ this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
2654
+ }
2655
+ /**
2656
+ * Middleware handler for processing requests.
2657
+ */
2658
+ use(_req, reply, next) {
2659
+ const correlationId = generateCorrelationId();
2660
+ if (this.includeInResponse) {
2661
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2662
+ }
2663
+ runWithCorrelationContext({
2664
+ correlationId
2665
+ }, () => {
2666
+ next();
2667
+ });
2668
+ }
2669
+ /**
2670
+ * Fastify hook handler for onRequest.
2671
+ * This is an async function that returns a Promise, ensuring the AsyncLocalStorage
2672
+ * context persists throughout the entire request lifecycle.
2673
+ */
2674
+ async onRequest(_req, reply) {
2675
+ const correlationId = generateCorrelationId();
2676
+ if (this.includeInResponse) {
2677
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2678
+ }
2679
+ const store = correlationStorage.getStore();
2680
+ if (!store) {
2681
+ correlationStorage.enterWith({
2682
+ correlationId
2683
+ });
2478
2684
  }
2479
2685
  }
2480
2686
  };
2481
-
2482
- // src/logger/logger.module.ts
2483
- import { Global as Global4, Module as Module5, Logger as Logger11 } from "@nestjs/common";
2687
+ CorrelationIdMiddleware = _ts_decorate15([
2688
+ Injectable10(),
2689
+ _ts_metadata8("design:type", Function),
2690
+ _ts_metadata8("design:paramtypes", [
2691
+ typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
2692
+ ])
2693
+ ], CorrelationIdMiddleware);
2484
2694
 
2485
2695
  // src/logger/services/logger.service.ts
2486
- import { Injectable as Injectable9, Logger as Logger10, Optional } from "@nestjs/common";
2696
+ import { Injectable as Injectable11, Optional as Optional2 } from "@nestjs/common";
2487
2697
  import { createLogger, format, transports } from "winston";
2488
2698
  import DailyRotateFile from "winston-daily-rotate-file";
2489
-
2490
- // src/logger/utils/index.ts
2491
- import { AsyncLocalStorage } from "async_hooks";
2492
- import { randomUUID } from "crypto";
2493
- var correlationStorage = new AsyncLocalStorage();
2494
- function getCorrelationContext() {
2495
- return correlationStorage.getStore();
2496
- }
2497
- __name(getCorrelationContext, "getCorrelationContext");
2498
- function runWithCorrelationContext(context, callback) {
2499
- return correlationStorage.run(context, callback);
2500
- }
2501
- __name(runWithCorrelationContext, "runWithCorrelationContext");
2502
- function updateCorrelationContext(updates) {
2503
- const context = correlationStorage.getStore();
2504
- if (context) {
2505
- Object.assign(context, updates);
2506
- }
2507
- }
2508
- __name(updateCorrelationContext, "updateCorrelationContext");
2509
- var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
2510
- function generateCorrelationId() {
2511
- return randomUUID();
2512
- }
2513
- __name(generateCorrelationId, "generateCorrelationId");
2514
- function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
2515
- if (typeof reply.header === "function") {
2516
- reply.header(headerName, correlationId);
2517
- } else if (reply.raw && typeof reply.raw.setHeader === "function") {
2518
- reply.raw.setHeader(headerName, correlationId);
2519
- }
2520
- }
2521
- __name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
2522
-
2523
- // src/logger/services/logger.service.ts
2524
- function _ts_decorate14(decorators, target, key, desc) {
2699
+ function _ts_decorate16(decorators, target, key, desc) {
2525
2700
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2526
2701
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2527
2702
  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;
2528
2703
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2529
2704
  }
2530
- __name(_ts_decorate14, "_ts_decorate");
2531
- function _ts_metadata8(k, v) {
2705
+ __name(_ts_decorate16, "_ts_decorate");
2706
+ function _ts_metadata9(k, v) {
2532
2707
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2533
2708
  }
2534
- __name(_ts_metadata8, "_ts_metadata");
2535
- function _ts_param4(paramIndex, decorator) {
2709
+ __name(_ts_metadata9, "_ts_metadata");
2710
+ function _ts_param5(paramIndex, decorator) {
2536
2711
  return function(target, key) {
2537
2712
  decorator(target, key, paramIndex);
2538
2713
  };
2539
2714
  }
2540
- __name(_ts_param4, "_ts_param");
2715
+ __name(_ts_param5, "_ts_param");
2541
2716
  var LoggerService2 = class _LoggerService {
2542
2717
  static {
2543
2718
  __name(this, "LoggerService");
@@ -2590,7 +2765,8 @@ var LoggerService2 = class _LoggerService {
2590
2765
  ].filter(Boolean);
2591
2766
  let output = parts.join(" ");
2592
2767
  if (trace) {
2593
- output += "\n" + trace;
2768
+ output += `
2769
+ ${trace}`;
2594
2770
  }
2595
2771
  return output;
2596
2772
  }), format.colorize({
@@ -2738,210 +2914,16 @@ var LoggerService2 = class _LoggerService {
2738
2914
  return childLogger;
2739
2915
  }
2740
2916
  };
2741
- LoggerService2 = _ts_decorate14([
2742
- Injectable9(),
2743
- _ts_param4(0, Optional()),
2744
- _ts_param4(1, Optional()),
2745
- _ts_metadata8("design:type", Function),
2746
- _ts_metadata8("design:paramtypes", [
2747
- typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
2748
- typeof Logger10 === "undefined" ? Object : Logger10
2749
- ])
2750
- ], LoggerService2);
2751
-
2752
- // src/logger/middleware/correlation-id.middleware.ts
2753
- import { Injectable as Injectable10 } from "@nestjs/common";
2754
- function _ts_decorate15(decorators, target, key, desc) {
2755
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2756
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2757
- 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;
2758
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2759
- }
2760
- __name(_ts_decorate15, "_ts_decorate");
2761
- function _ts_metadata9(k, v) {
2762
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2763
- }
2764
- __name(_ts_metadata9, "_ts_metadata");
2765
- var CorrelationIdMiddleware = class {
2766
- static {
2767
- __name(this, "CorrelationIdMiddleware");
2768
- }
2769
- includeInResponse;
2770
- responseHeader;
2771
- constructor(options = {}) {
2772
- this.includeInResponse = options.includeInResponse ?? true;
2773
- this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
2774
- }
2775
- /**
2776
- * Middleware handler for processing requests.
2777
- */
2778
- use(req, reply, next) {
2779
- const correlationId = generateCorrelationId();
2780
- if (this.includeInResponse) {
2781
- addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2782
- }
2783
- runWithCorrelationContext({
2784
- correlationId
2785
- }, () => {
2786
- next();
2787
- });
2788
- }
2789
- /**
2790
- * Fastify hook handler for onRequest.
2791
- * This is an async function that returns a Promise, ensuring the AsyncLocalStorage
2792
- * context persists throughout the entire request lifecycle.
2793
- */
2794
- async onRequest(req, reply) {
2795
- const correlationId = generateCorrelationId();
2796
- if (this.includeInResponse) {
2797
- addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2798
- }
2799
- const store = correlationStorage.getStore();
2800
- if (!store) {
2801
- correlationStorage.enterWith({
2802
- correlationId
2803
- });
2804
- }
2805
- }
2806
- };
2807
- CorrelationIdMiddleware = _ts_decorate15([
2808
- Injectable10(),
2809
- _ts_metadata9("design:type", Function),
2810
- _ts_metadata9("design:paramtypes", [
2811
- typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
2812
- ])
2813
- ], CorrelationIdMiddleware);
2814
-
2815
- // src/logger/interceptors/http-logger.interceptor.ts
2816
- import { Injectable as Injectable11, Optional as Optional2 } from "@nestjs/common";
2817
- import { tap as tap2, catchError } from "rxjs/operators";
2818
- function _ts_decorate16(decorators, target, key, desc) {
2819
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2820
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2821
- 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;
2822
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2823
- }
2824
- __name(_ts_decorate16, "_ts_decorate");
2825
- function _ts_metadata10(k, v) {
2826
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2827
- }
2828
- __name(_ts_metadata10, "_ts_metadata");
2829
- function _ts_param5(paramIndex, decorator) {
2830
- return function(target, key) {
2831
- decorator(target, key, paramIndex);
2832
- };
2833
- }
2834
- __name(_ts_param5, "_ts_param");
2835
- var HttpLoggerInterceptor = class {
2836
- static {
2837
- __name(this, "HttpLoggerInterceptor");
2838
- }
2839
- logger;
2840
- enableRequestLog;
2841
- enableResponseLog;
2842
- slowRequestThreshold;
2843
- constructor(logger, options) {
2844
- this.logger = logger;
2845
- this.enableRequestLog = options?.enableRequestLog ?? true;
2846
- this.enableResponseLog = options?.enableResponseLog ?? true;
2847
- this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
2848
- }
2849
- intercept(context, next) {
2850
- if (context.getType() !== "http") {
2851
- return next.handle();
2852
- }
2853
- const httpContext = context.switchToHttp();
2854
- const request = httpContext.getRequest();
2855
- const response = httpContext.getResponse();
2856
- const startTime = Date.now();
2857
- if (this.enableRequestLog) {
2858
- this.logRequest(request);
2859
- }
2860
- return next.handle().pipe(tap2(() => {
2861
- if (this.enableResponseLog) {
2862
- const duration = Date.now() - startTime;
2863
- this.logResponse(request, response, duration);
2864
- }
2865
- }), catchError((error) => {
2866
- const duration = Date.now() - startTime;
2867
- this.logError(request, response, duration, error);
2868
- throw error;
2869
- }));
2870
- }
2871
- logRequest(request) {
2872
- try {
2873
- const correlationContext = getCorrelationContext();
2874
- const metadata = {
2875
- type: "http_request",
2876
- method: request.method,
2877
- url: request.url,
2878
- correlationId: correlationContext?.correlationId,
2879
- ip: request.ip,
2880
- userAgent: request.headers["user-agent"]
2881
- };
2882
- this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
2883
- } catch (error) {
2884
- this.logger.error("Failed to log HTTP request", error.stack);
2885
- }
2886
- }
2887
- logResponse(request, response, duration) {
2888
- try {
2889
- const correlationContext = getCorrelationContext();
2890
- const statusCode = response.statusCode;
2891
- const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
2892
- const metadata = {
2893
- type: "http_response",
2894
- method: request.method,
2895
- url: request.url,
2896
- statusCode,
2897
- duration,
2898
- correlationId: correlationContext?.correlationId
2899
- };
2900
- if (duration > this.slowRequestThreshold) {
2901
- metadata.slowRequest = true;
2902
- }
2903
- const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
2904
- this.logger.logWithMetadata(logLevel, message, metadata);
2905
- } catch (error) {
2906
- this.logger.error("Failed to log HTTP response", error.stack);
2907
- }
2908
- }
2909
- logError(request, response, duration, error) {
2910
- try {
2911
- const correlationContext = getCorrelationContext();
2912
- const statusCode = response.statusCode || 500;
2913
- const metadata = {
2914
- type: "http_error",
2915
- method: request.method,
2916
- url: request.url,
2917
- statusCode,
2918
- duration,
2919
- correlationId: correlationContext?.correlationId,
2920
- errorName: error?.name || "Error",
2921
- errorMessage: error?.message || "Unknown error"
2922
- };
2923
- if (error?.stack) {
2924
- metadata.trace = error.stack;
2925
- }
2926
- if (error?.response) {
2927
- metadata.errorDetails = error.response;
2928
- }
2929
- const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
2930
- this.logger.logWithMetadata("error", message, metadata);
2931
- } catch (loggingError) {
2932
- this.logger.error("Failed to log HTTP error", loggingError.stack);
2933
- }
2934
- }
2935
- };
2936
- HttpLoggerInterceptor = _ts_decorate16([
2917
+ LoggerService2 = _ts_decorate16([
2937
2918
  Injectable11(),
2919
+ _ts_param5(0, Optional2()),
2938
2920
  _ts_param5(1, Optional2()),
2939
- _ts_metadata10("design:type", Function),
2940
- _ts_metadata10("design:paramtypes", [
2941
- typeof LoggerService === "undefined" ? Object : LoggerService,
2942
- typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
2921
+ _ts_metadata9("design:type", Function),
2922
+ _ts_metadata9("design:paramtypes", [
2923
+ typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
2924
+ typeof Logger === "undefined" ? Object : Logger
2943
2925
  ])
2944
- ], HttpLoggerInterceptor);
2926
+ ], LoggerService2);
2945
2927
 
2946
2928
  // src/logger/logger.module.ts
2947
2929
  function _ts_decorate17(decorators, target, key, desc) {
@@ -3214,7 +3196,7 @@ var LoggerModule = class _LoggerModule {
3214
3196
  * ```
3215
3197
  */
3216
3198
  static forRootAsync(options) {
3217
- const asyncProviders = this.createAsyncProviders(options);
3199
+ const asyncProviders = _LoggerModule.createAsyncProviders(options);
3218
3200
  return {
3219
3201
  module: _LoggerModule,
3220
3202
  imports: options.imports || [],
@@ -3290,7 +3272,7 @@ var LoggerModule = class _LoggerModule {
3290
3272
  * Configures middleware for the module.
3291
3273
  * Middleware is registered globally in main.ts using Fastify hooks.
3292
3274
  */
3293
- configure(consumer) {
3275
+ configure(_consumer) {
3294
3276
  }
3295
3277
  /**
3296
3278
  * Creates async providers for dynamic module configuration.
@@ -3298,11 +3280,11 @@ var LoggerModule = class _LoggerModule {
3298
3280
  static createAsyncProviders(options) {
3299
3281
  if (options.useFactory) {
3300
3282
  return [
3301
- this.createAsyncOptionsProvider(options)
3283
+ _LoggerModule.createAsyncOptionsProvider(options)
3302
3284
  ];
3303
3285
  }
3304
3286
  const providers = [
3305
- this.createAsyncOptionsProvider(options)
3287
+ _LoggerModule.createAsyncOptionsProvider(options)
3306
3288
  ];
3307
3289
  if (options.useClass) {
3308
3290
  providers.push({
@@ -3320,7 +3302,7 @@ var LoggerModule = class _LoggerModule {
3320
3302
  return {
3321
3303
  provide: LOGGER_MODULE_OPTIONS,
3322
3304
  useFactory: /* @__PURE__ */ __name(async (...args) => {
3323
- const userOptions = await options.useFactory(...args);
3305
+ const userOptions = await options.useFactory?.(...args);
3324
3306
  return mergeWithDefaults(userOptions);
3325
3307
  }, "useFactory"),
3326
3308
  inject: options.inject || []
@@ -3367,7 +3349,7 @@ export {
3367
3349
  CsrfGuard,
3368
3350
  DEFAULT_CORRELATION_HEADER,
3369
3351
  DatabaseModule,
3370
- ForbiddenException2 as ForbiddenException,
3352
+ ForbiddenException,
3371
3353
  GoneException,
3372
3354
  HttpExceptionFilter,
3373
3355
  HttpLoggerInterceptor,
@@ -3383,13 +3365,13 @@ export {
3383
3365
  Onboarding,
3384
3366
  PayloadTooLargeException,
3385
3367
  PrimaryBaseRepository,
3386
- PrimaryDatabaseService,
3368
+ PrimaryDatabaseService2 as PrimaryDatabaseService,
3387
3369
  Public,
3388
3370
  RequestTimeoutException,
3389
3371
  ServiceUnavailableException,
3390
3372
  Tenant,
3391
3373
  TenantBaseRepository,
3392
- TenantContextService,
3374
+ TenantContextService2 as TenantContextService,
3393
3375
  TenantDatabaseService,
3394
3376
  TooManyRequestsException,
3395
3377
  UnauthorizedException4 as UnauthorizedException,