@vritti/api-sdk 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -36,13 +36,19 @@ __export(index_exports, {
36
36
  BadRequestException: () => BadRequestException,
37
37
  BaseFieldException: () => BaseFieldException,
38
38
  ConflictException: () => ConflictException,
39
+ CorrelationIdMiddleware: () => CorrelationIdMiddleware,
39
40
  CsrfGuard: () => CsrfGuard,
41
+ DEFAULT_CORRELATION_HEADER: () => DEFAULT_CORRELATION_HEADER,
40
42
  DatabaseModule: () => DatabaseModule,
41
43
  ForbiddenException: () => ForbiddenException2,
42
44
  GoneException: () => GoneException,
43
45
  HttpExceptionFilter: () => HttpExceptionFilter,
46
+ HttpLoggerInterceptor: () => HttpLoggerInterceptor,
44
47
  HttpModule: () => HttpModule,
45
48
  InternalServerErrorException: () => InternalServerErrorException3,
49
+ LOGGER_MODULE_OPTIONS: () => LOGGER_MODULE_OPTIONS,
50
+ LoggerModule: () => LoggerModule,
51
+ LoggerService: () => LoggerService2,
46
52
  MethodNotAllowedException: () => MethodNotAllowedException,
47
53
  NotAcceptableException: () => NotAcceptableException,
48
54
  NotFoundException: () => NotFoundException,
@@ -64,7 +70,13 @@ __export(index_exports, {
64
70
  UnsupportedMediaTypeException: () => UnsupportedMediaTypeException,
65
71
  ValidationException: () => ValidationException,
66
72
  VrittiAuthGuard: () => VrittiAuthGuard,
67
- getHttpStatusTitle: () => getHttpStatusTitle
73
+ addCorrelationIdToResponse: () => addCorrelationIdToResponse,
74
+ correlationStorage: () => correlationStorage,
75
+ generateCorrelationId: () => generateCorrelationId,
76
+ getCorrelationContext: () => getCorrelationContext,
77
+ getHttpStatusTitle: () => getHttpStatusTitle,
78
+ runWithCorrelationContext: () => runWithCorrelationContext,
79
+ updateCorrelationContext: () => updateCorrelationContext
68
80
  });
69
81
  module.exports = __toCommonJS(index_exports);
70
82
 
@@ -210,6 +222,9 @@ var jwt = __toESM(require("jsonwebtoken"), 1);
210
222
 
211
223
  // src/database/services/primary-database.service.ts
212
224
  var import_common3 = require("@nestjs/common");
225
+ var import_pg = require("pg");
226
+ var import_node_postgres = require("drizzle-orm/node-postgres");
227
+ var import_drizzle_orm = require("drizzle-orm");
213
228
 
214
229
  // src/database/constants.ts
215
230
  var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
@@ -238,8 +253,10 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
238
253
  }
239
254
  options;
240
255
  logger = new import_common3.Logger(_PrimaryDatabaseService.name);
241
- /** Primary database client for querying tenant registry */
242
- primaryDbClient;
256
+ /** PostgreSQL connection pool */
257
+ pool = null;
258
+ /** Drizzle database instance */
259
+ db = null;
243
260
  /** In-memory cache: Map<tenantIdentifier, TenantConfig> */
244
261
  tenantConfigCache = /* @__PURE__ */ new Map();
245
262
  /** Cache TTL in milliseconds */
@@ -250,28 +267,24 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
250
267
  }
251
268
  async onModuleInit() {
252
269
  if (this.options.primaryDb) {
253
- await this.initializePrimaryDbClient();
270
+ await this.initializeDrizzleClient();
254
271
  }
255
272
  }
256
273
  /**
257
- * Initialize connection to primary database
274
+ * Initialize connection to primary database using Drizzle
258
275
  */
259
- async initializePrimaryDbClient() {
276
+ async initializeDrizzleClient() {
260
277
  try {
261
- const PrimaryDbClient = this.options.prismaClientConstructor;
262
278
  const databaseUrl = this.buildPrimaryDbUrl();
263
- this.primaryDbClient = new PrimaryDbClient({
264
- datasources: {
265
- db: {
266
- url: databaseUrl
267
- }
268
- },
269
- log: [
270
- "error",
271
- "warn"
272
- ]
279
+ this.pool = new import_pg.Pool({
280
+ connectionString: databaseUrl,
281
+ max: this.options.maxConnections || 10
273
282
  });
274
- await this.primaryDbClient.$connect();
283
+ this.db = (0, import_node_postgres.drizzle)({
284
+ client: this.pool,
285
+ schema: this.options.drizzleSchema
286
+ });
287
+ await this.pool.query("SELECT 1");
275
288
  this.logger.log("Connected to primary database (tenant registry)");
276
289
  } catch (error) {
277
290
  this.logger.error("Failed to connect to primary database", error);
@@ -286,7 +299,7 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
286
299
  throw new Error("Primary database configuration not provided");
287
300
  }
288
301
  const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
289
- let url = `postgresql://${username}:${password}@${host}:${port}/${database}`;
302
+ let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
290
303
  const params = new URLSearchParams();
291
304
  if (schema) {
292
305
  params.set("schema", schema);
@@ -306,9 +319,9 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
306
319
  return url.replace(/:([^@]+)@/, ":****@");
307
320
  }
308
321
  /**
309
- * Get tenant configuration by identifier (ID or slug)
322
+ * Get tenant configuration by identifier (ID or subdomain)
310
323
  *
311
- * @param tenantIdentifier Tenant ID or slug
324
+ * @param tenantIdentifier Tenant ID or subdomain
312
325
  * @returns Tenant configuration or null if not found
313
326
  */
314
327
  async getTenantInfo(tenantIdentifier) {
@@ -318,45 +331,39 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
318
331
  return cached;
319
332
  }
320
333
  try {
321
- if (!this.primaryDbClient) {
334
+ if (!this.db) {
322
335
  throw new Error("Primary database client not initialized");
323
336
  }
324
337
  this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
325
- const tenant = await this.primaryDbClient.tenant.findFirst({
326
- where: {
327
- OR: [
328
- {
329
- id: tenantIdentifier
330
- },
331
- {
332
- subdomain: tenantIdentifier
333
- }
334
- ],
335
- status: "ACTIVE"
336
- },
337
- include: {
338
- databaseConfig: true
339
- }
340
- });
341
- if (!tenant) {
338
+ const schema = this.options.drizzleSchema;
339
+ const { tenants, tenantDatabaseConfigs } = schema;
340
+ const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, (0, import_drizzle_orm.eq)(tenants.id, tenantDatabaseConfigs.tenantId)).where((0, import_drizzle_orm.or)((0, import_drizzle_orm.eq)(tenants.id, tenantIdentifier), (0, import_drizzle_orm.eq)(tenants.subdomain, tenantIdentifier))).limit(1);
341
+ if (!result.length) {
342
342
  this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
343
343
  return null;
344
344
  }
345
+ const row = result[0];
346
+ const tenant = row.tenants;
347
+ const config = row.tenant_database_configs;
348
+ if (tenant.status !== "ACTIVE") {
349
+ this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
350
+ return null;
351
+ }
345
352
  const info = {
346
353
  id: tenant.id,
347
354
  subdomain: tenant.subdomain,
348
355
  type: tenant.dbType,
349
356
  status: tenant.status,
350
357
  // For SHARED tenants: schema name
351
- schemaName: tenant.databaseConfig?.dbSchema || void 0,
358
+ schemaName: config?.dbSchema || void 0,
352
359
  // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
353
- databaseName: tenant.databaseConfig?.dbName || void 0,
354
- databaseHost: tenant.databaseConfig?.dbHost || void 0,
355
- databasePort: tenant.databaseConfig?.dbPort || void 0,
356
- databaseUsername: tenant.databaseConfig?.dbUsername ? this.decrypt(tenant.databaseConfig.dbUsername) : void 0,
357
- databasePassword: tenant.databaseConfig?.dbPassword ? this.decrypt(tenant.databaseConfig.dbPassword) : void 0,
358
- databaseSslMode: tenant.databaseConfig?.dbSslMode || void 0,
359
- connectionPoolSize: tenant.databaseConfig?.connectionPoolSize || void 0
360
+ databaseName: config?.dbName || void 0,
361
+ databaseHost: config?.dbHost || void 0,
362
+ databasePort: config?.dbPort || void 0,
363
+ databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
364
+ databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
365
+ databaseSslMode: config?.dbSslMode || void 0,
366
+ connectionPoolSize: config?.connectionPoolSize || void 0
360
367
  };
361
368
  this.cacheInfo(info);
362
369
  return info;
@@ -382,7 +389,7 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
382
389
  *
383
390
  * Useful when tenant settings are updated and cache needs to be invalidated
384
391
  *
385
- * @param tenantIdentifier Tenant ID or slug
392
+ * @param tenantIdentifier Tenant ID or subdomain
386
393
  */
387
394
  clearTenantCache(tenantIdentifier) {
388
395
  const config = this.tenantConfigCache.get(tenantIdentifier);
@@ -401,17 +408,23 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
401
408
  this.logger.log(`Cleared ${size} cached tenant configs`);
402
409
  }
403
410
  /**
404
- * Get the Prisma client for the primary database.
405
- * This is a synchronous property that returns the initialized Prisma client.
411
+ * Get the Drizzle database instance for the primary database.
412
+ * This is a synchronous property that returns the initialized Drizzle client.
406
413
  *
407
- * @returns Primary database client instance
414
+ * @returns Primary database Drizzle instance
408
415
  * @throws Error if primary database client is not initialized
409
416
  */
410
- get prismaClient() {
411
- if (!this.primaryDbClient) {
417
+ get drizzleClient() {
418
+ if (!this.db) {
412
419
  throw new Error("Primary database client not initialized");
413
420
  }
414
- return this.primaryDbClient;
421
+ return this.db;
422
+ }
423
+ /**
424
+ * Get the Drizzle schema
425
+ */
426
+ get schema() {
427
+ return this.options.drizzleSchema;
415
428
  }
416
429
  /**
417
430
  * Decrypt database credentials
@@ -425,8 +438,8 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
425
438
  return encrypted;
426
439
  }
427
440
  async onModuleDestroy() {
428
- if (this.primaryDbClient) {
429
- await this.primaryDbClient.$disconnect();
441
+ if (this.pool) {
442
+ await this.pool.end();
430
443
  this.logger.log("Disconnected from primary database");
431
444
  }
432
445
  }
@@ -971,6 +984,8 @@ TenantContextInterceptor = _ts_decorate8([
971
984
 
972
985
  // src/database/services/tenant-database.service.ts
973
986
  var import_common9 = require("@nestjs/common");
987
+ var import_pg2 = require("pg");
988
+ var import_node_postgres2 = require("drizzle-orm/node-postgres");
974
989
  function _ts_decorate9(decorators, target, key, desc) {
975
990
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
976
991
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -995,7 +1010,7 @@ var TenantDatabaseService = class _TenantDatabaseService {
995
1010
  options;
996
1011
  tenantContext;
997
1012
  logger = new import_common9.Logger(_TenantDatabaseService.name);
998
- /** Connection pool: Map<cacheKey, DbClient> */
1013
+ /** Connection pool: Map<cacheKey, TenantConnection> */
999
1014
  clients = /* @__PURE__ */ new Map();
1000
1015
  /** Track last usage time for idle connection cleanup */
1001
1016
  clientLastUsed = /* @__PURE__ */ new Map();
@@ -1007,17 +1022,23 @@ var TenantDatabaseService = class _TenantDatabaseService {
1007
1022
  this.startConnectionCleaner();
1008
1023
  }
1009
1024
  /**
1010
- * Get the Prisma client for the current tenant's database.
1025
+ * Get the Drizzle client for the current tenant's database.
1011
1026
  * This returns the tenant-scoped database client.
1012
1027
  *
1013
- * @returns Tenant-scoped database client instance
1028
+ * @returns Tenant-scoped Drizzle database instance
1014
1029
  * @throws UnauthorizedException if tenant context not set
1015
1030
  * @throws InternalServerErrorException if connection fails
1016
1031
  */
1017
- get prismaClient() {
1032
+ get drizzleClient() {
1018
1033
  return this.getDbClient();
1019
1034
  }
1020
1035
  /**
1036
+ * Get the Drizzle schema
1037
+ */
1038
+ get schema() {
1039
+ return this.options.drizzleSchema;
1040
+ }
1041
+ /**
1021
1042
  * Get tenant-scoped database client for the current request/message
1022
1043
  *
1023
1044
  * This method:
@@ -1025,66 +1046,61 @@ var TenantDatabaseService = class _TenantDatabaseService {
1025
1046
  * 2. Builds a connection URL based on tenant type
1026
1047
  * 3. Returns cached client if exists, otherwise creates new one
1027
1048
  *
1028
- * @returns Promise<Database client instance>
1049
+ * @returns Drizzle database instance
1029
1050
  * @throws UnauthorizedException if tenant context not set
1030
1051
  * @throws InternalServerErrorException if connection fails
1031
- *
1032
- * @example
1033
- * const dbClient = await tenantDatabase.getDbClient<PrismaClient>();
1034
- * const users = await dbClient.user.findMany();
1035
1052
  */
1036
- async getDbClient() {
1053
+ getDbClient() {
1037
1054
  const tenant = this.tenantContext.getTenant();
1038
1055
  const cacheKey = this.buildCacheKey(tenant);
1039
- if (this.clients.has(cacheKey)) {
1056
+ const existing = this.clients.get(cacheKey);
1057
+ if (existing) {
1040
1058
  this.clientLastUsed.set(cacheKey, Date.now());
1041
1059
  this.logger.debug(`Reusing cached connection: ${cacheKey}`);
1042
- return this.clients.get(cacheKey);
1060
+ return existing.db;
1043
1061
  }
1044
1062
  this.logger.log(`Creating new database connection: ${cacheKey}`);
1045
- const client = await this.createDbClient(tenant);
1046
- this.clients.set(cacheKey, client);
1063
+ const connection = this.createDbClientSync(tenant);
1064
+ this.clients.set(cacheKey, connection);
1047
1065
  this.clientLastUsed.set(cacheKey, Date.now());
1048
- return client;
1066
+ return connection.db;
1049
1067
  }
1050
1068
  /**
1051
- * Create a new database client for the given tenant
1069
+ * Create a new database client for the given tenant (synchronous)
1052
1070
  */
1053
- async createDbClient(tenant) {
1071
+ createDbClientSync(tenant) {
1054
1072
  try {
1055
1073
  const databaseUrl = this.buildTenantDbUrl(tenant);
1056
- const PrismaClient = await this.options.prismaClientConstructor;
1057
- const client = new PrismaClient({
1058
- datasources: {
1059
- db: {
1060
- url: databaseUrl
1061
- }
1062
- },
1063
- log: [
1064
- "error",
1065
- "warn"
1066
- ]
1074
+ const pool = new import_pg2.Pool({
1075
+ connectionString: databaseUrl,
1076
+ max: tenant.connectionPoolSize || this.options.maxConnections || 10
1077
+ });
1078
+ const db = (0, import_node_postgres2.drizzle)({
1079
+ client: pool,
1080
+ schema: this.options.drizzleSchema
1067
1081
  });
1068
- await client.$connect();
1069
1082
  this.logger.log(`Connected to database for tenant: ${tenant.subdomain}`);
1070
- return client;
1083
+ return {
1084
+ pool,
1085
+ db
1086
+ };
1071
1087
  } catch (error) {
1072
1088
  this.logger.error(`Failed to create database connection for tenant: ${tenant.subdomain}`, error);
1073
1089
  throw new import_common9.InternalServerErrorException("Failed to connect to tenant database");
1074
1090
  }
1075
1091
  }
1076
1092
  /**
1077
- * Build connection URL for enterprise tenant (dedicated database)
1093
+ * Build connection URL for tenant (dedicated database)
1078
1094
  */
1079
1095
  buildTenantDbUrl(tenant) {
1080
1096
  const { databaseHost, databasePort, databaseName, databaseUsername, databasePassword, databaseSslMode } = tenant;
1081
1097
  if (!databaseHost || !databaseName || !databaseUsername) {
1082
- throw new Error(`Enterprise tenant ${tenant.subdomain} missing database configuration`);
1098
+ throw new Error(`Tenant ${tenant.subdomain} missing database configuration`);
1083
1099
  }
1084
1100
  const port = databasePort || 5432;
1085
1101
  const sslMode = databaseSslMode || "require";
1086
- const connectionUrl = `postgresql://${databaseUsername}:${databasePassword}@${databaseHost}:${port}/${databaseName}?sslmode=${sslMode}`;
1087
- this.logger.debug(`Enterprise connection URL: ${this.maskPassword(connectionUrl)}`);
1102
+ const connectionUrl = `postgresql://${databaseUsername}:${encodeURIComponent(databasePassword || "")}@${databaseHost}:${port}/${databaseName}?sslmode=${sslMode}`;
1103
+ this.logger.debug(`Tenant connection URL: ${this.maskPassword(connectionUrl)}`);
1088
1104
  return connectionUrl;
1089
1105
  }
1090
1106
  /**
@@ -1106,19 +1122,20 @@ var TenantDatabaseService = class _TenantDatabaseService {
1106
1122
  /**
1107
1123
  * Clean up idle connections that haven't been used recently
1108
1124
  */
1109
- cleanupIdleConnections() {
1125
+ async cleanupIdleConnections() {
1110
1126
  const now = Date.now();
1111
1127
  const maxIdle = this.options.connectionCacheTTL || 3e5;
1112
1128
  let cleaned = 0;
1113
1129
  for (const [key, lastUsed] of this.clientLastUsed.entries()) {
1114
1130
  if (now - lastUsed > maxIdle) {
1115
- const client = this.clients.get(key);
1116
- if (client) {
1117
- client.$disconnect().then(() => {
1131
+ const connection = this.clients.get(key);
1132
+ if (connection) {
1133
+ try {
1134
+ await connection.pool.end();
1118
1135
  this.logger.debug(`Cleaned up idle connection: ${key}`);
1119
- }).catch((error) => {
1136
+ } catch (error) {
1120
1137
  this.logger.error(`Error disconnecting idle client: ${key}`, error);
1121
- });
1138
+ }
1122
1139
  this.clients.delete(key);
1123
1140
  this.clientLastUsed.delete(key);
1124
1141
  cleaned++;
@@ -1149,9 +1166,9 @@ var TenantDatabaseService = class _TenantDatabaseService {
1149
1166
  clearInterval(this.cleanupInterval);
1150
1167
  }
1151
1168
  this.logger.log(`Disconnecting ${this.clients.size} database connections`);
1152
- const disconnectPromises = Array.from(this.clients.entries()).map(async ([key, client]) => {
1169
+ const disconnectPromises = Array.from(this.clients.entries()).map(async ([key, connection]) => {
1153
1170
  try {
1154
- await client.$disconnect();
1171
+ await connection.pool.end();
1155
1172
  this.logger.debug(`Disconnected: ${key}`);
1156
1173
  } catch (error) {
1157
1174
  this.logger.error(`Error disconnecting client: ${key}`, error);
@@ -1287,56 +1304,64 @@ DatabaseModule = _ts_decorate10([
1287
1304
 
1288
1305
  // src/database/repositories/primary-base.repository.ts
1289
1306
  var import_common11 = require("@nestjs/common");
1307
+ var import_drizzle_orm2 = require("drizzle-orm");
1290
1308
  var PrimaryBaseRepository = class {
1291
1309
  static {
1292
1310
  __name(this, "PrimaryBaseRepository");
1293
1311
  }
1294
1312
  database;
1313
+ table;
1295
1314
  logger;
1296
- modelGetter;
1297
1315
  /**
1298
- * Lazy getter for Prisma client.
1316
+ * The table name extracted from the Drizzle table at runtime.
1317
+ * Used to access the query API for this repository's table.
1318
+ */
1319
+ tableName;
1320
+ /**
1321
+ * Lazy getter for Drizzle client.
1299
1322
  * Accesses the client from the database service only when needed,
1300
1323
  * avoiding initialization timing issues with NestJS lifecycle.
1301
1324
  */
1302
- get prisma() {
1303
- return this.database.prismaClient;
1325
+ get db() {
1326
+ return this.database.drizzleClient;
1304
1327
  }
1305
1328
  /**
1306
- * Lazy getter for the Prisma model delegate.
1307
- * Returns the specific model (e.g., prisma.user, prisma.tenant) for this repository.
1329
+ * Model query API for THIS repository's table (Prisma-like syntax)
1330
+ * Scoped to only the table this repository manages.
1331
+ * Returns a type-safe wrapper around Drizzle's RelationalQueryBuilder.
1332
+ *
1333
+ * @example
1334
+ * ```typescript
1335
+ * // Use relational queries with type safety
1336
+ * const user = await this.model.findFirst({
1337
+ * where: eq(users.id, id),
1338
+ * with: { posts: true, profile: true }
1339
+ * });
1340
+ * ```
1308
1341
  */
1309
1342
  get model() {
1310
- return this.modelGetter(this.prisma);
1343
+ return this.database.drizzleClient.query[this.tableName];
1311
1344
  }
1312
1345
  /**
1313
1346
  * Create a new repository instance
1314
1347
  *
1315
1348
  * @param database - The primary database service
1316
- * @param getModel - Function that returns the Prisma model delegate from the client
1349
+ * @param table - The Drizzle table schema object
1317
1350
  *
1318
1351
  * @example
1319
1352
  * ```typescript
1320
- * // Standard usage with full parameter name
1321
- * constructor(database: PrimaryDatabaseService) {
1322
- * super(database, (prisma) => prisma.user);
1323
- * }
1324
- *
1325
- * // Short syntax
1326
- * constructor(database: PrimaryDatabaseService) {
1327
- * super(database, (p) => p.user);
1328
- * }
1353
+ * import { users } from '@/db/schema';
1329
1354
  *
1330
- * // Complex model names
1331
1355
  * constructor(database: PrimaryDatabaseService) {
1332
- * super(database, (p) => p.emailVerification);
1356
+ * super(database, users);
1333
1357
  * }
1334
1358
  * ```
1335
1359
  */
1336
- constructor(database, getModel) {
1360
+ constructor(database, table) {
1337
1361
  this.database = database;
1362
+ this.table = table;
1363
+ this.tableName = (0, import_drizzle_orm2.getTableName)(table);
1338
1364
  this.logger = new import_common11.Logger(this.constructor.name);
1339
- this.modelGetter = getModel;
1340
1365
  this.logger.debug(`Initialized ${this.constructor.name}`);
1341
1366
  }
1342
1367
  /**
@@ -1349,21 +1374,20 @@ var PrimaryBaseRepository = class {
1349
1374
  * ```typescript
1350
1375
  * const user = await userRepository.create({
1351
1376
  * email: 'user@example.com',
1352
- * name: 'John Doe'
1377
+ * firstName: 'John'
1353
1378
  * });
1354
1379
  * ```
1355
1380
  */
1356
1381
  async create(data) {
1357
1382
  this.logger.log("Creating record");
1358
- return await this.model.create({
1359
- data
1360
- });
1383
+ const results = await this.db.insert(this.table).values(data).returning();
1384
+ return results[0];
1361
1385
  }
1362
1386
  /**
1363
1387
  * Find a single record by ID
1364
1388
  *
1365
1389
  * @param id - The record ID
1366
- * @returns Promise resolving to the record or null if not found
1390
+ * @returns Promise resolving to the record or undefined if not found
1367
1391
  *
1368
1392
  * @example
1369
1393
  * ```typescript
@@ -1372,59 +1396,54 @@ var PrimaryBaseRepository = class {
1372
1396
  */
1373
1397
  async findById(id) {
1374
1398
  this.logger.debug(`Finding record by ID: ${id}`);
1375
- return await this.model.findUnique({
1376
- where: {
1377
- id
1378
- }
1399
+ const idColumn = this.table.id;
1400
+ return this.model.findFirst({
1401
+ where: (0, import_drizzle_orm2.eq)(idColumn, id)
1379
1402
  });
1380
1403
  }
1381
1404
  /**
1382
1405
  * Find a single record with custom where clause
1383
1406
  *
1384
- * @param where - The where clause or findUnique args
1385
- * @returns Promise resolving to the record or null if not found
1407
+ * @param where - SQL condition
1408
+ * @returns Promise resolving to the record or undefined if not found
1386
1409
  *
1387
1410
  * @example
1388
1411
  * ```typescript
1389
- * // Simple where clause
1390
- * const user = await userRepository.findOne({ email: 'user@example.com' });
1391
- *
1392
- * // With include
1393
- * const user = await userRepository.findOne({
1394
- * where: { email: 'user@example.com' },
1395
- * include: { posts: true }
1396
- * });
1412
+ * import { eq } from 'drizzle-orm';
1413
+ * const user = await userRepository.findOne(eq(users.email, 'user@example.com'));
1397
1414
  * ```
1398
1415
  */
1399
1416
  async findOne(where) {
1400
1417
  this.logger.debug("Finding record with custom query");
1401
- return await this.model.findUnique(typeof where === "object" && "where" in where ? where : {
1418
+ return this.model.findFirst({
1402
1419
  where
1403
1420
  });
1404
1421
  }
1405
1422
  /**
1406
1423
  * Find multiple records
1407
1424
  *
1408
- * @param args - Prisma findMany arguments (where, orderBy, take, skip, etc.)
1425
+ * @param options - Query options (where, orderBy, limit, offset)
1409
1426
  * @returns Promise resolving to an array of records
1410
1427
  *
1411
1428
  * @example
1412
1429
  * ```typescript
1430
+ * import { eq, desc } from 'drizzle-orm';
1431
+ *
1413
1432
  * // Find all users
1414
1433
  * const users = await userRepository.findMany();
1415
1434
  *
1416
1435
  * // Find with filtering and pagination
1417
1436
  * const users = await userRepository.findMany({
1418
- * where: { status: 'ACTIVE' },
1419
- * orderBy: { createdAt: 'desc' },
1420
- * take: 10,
1421
- * skip: 0
1437
+ * where: eq(users.accountStatus, 'ACTIVE'),
1438
+ * orderBy: desc(users.createdAt),
1439
+ * limit: 10,
1440
+ * offset: 0
1422
1441
  * });
1423
1442
  * ```
1424
1443
  */
1425
- async findMany(args) {
1444
+ async findMany(options) {
1426
1445
  this.logger.debug("Finding multiple records");
1427
- return await this.model.findMany(args);
1446
+ return this.model.findMany(options);
1428
1447
  }
1429
1448
  /**
1430
1449
  * Update a record by ID
@@ -1436,41 +1455,40 @@ var PrimaryBaseRepository = class {
1436
1455
  * @example
1437
1456
  * ```typescript
1438
1457
  * const user = await userRepository.update('user-id-123', {
1439
- * name: 'Jane Doe'
1458
+ * firstName: 'Jane'
1440
1459
  * });
1441
1460
  * ```
1442
1461
  */
1443
1462
  async update(id, data) {
1444
1463
  this.logger.log(`Updating record with ID: ${id}`);
1445
- return await this.model.update({
1446
- where: {
1447
- id
1448
- },
1449
- data
1450
- });
1464
+ const idColumn = this.table.id;
1465
+ const results = await this.db.update(this.table).set(data).where((0, import_drizzle_orm2.eq)(idColumn, id)).returning();
1466
+ return results[0];
1451
1467
  }
1452
1468
  /**
1453
1469
  * Update multiple records
1454
1470
  *
1455
- * @param where - The where clause to match records
1471
+ * @param where - SQL condition to match records
1456
1472
  * @param data - The data to update
1457
1473
  * @returns Promise resolving to the count of updated records
1458
1474
  *
1459
1475
  * @example
1460
1476
  * ```typescript
1477
+ * import { eq } from 'drizzle-orm';
1478
+ *
1461
1479
  * const result = await userRepository.updateMany(
1462
- * { status: 'PENDING' },
1463
- * { status: 'ACTIVE' }
1480
+ * eq(users.accountStatus, 'PENDING'),
1481
+ * { accountStatus: 'ACTIVE' }
1464
1482
  * );
1465
1483
  * console.log(`Updated ${result.count} users`);
1466
1484
  * ```
1467
1485
  */
1468
1486
  async updateMany(where, data) {
1469
1487
  this.logger.log("Updating multiple records");
1470
- return await this.model.updateMany({
1471
- where,
1472
- data
1473
- });
1488
+ const result = await this.db.update(this.table).set(data).where(where);
1489
+ return {
1490
+ count: result.rowCount ?? 0
1491
+ };
1474
1492
  }
1475
1493
  /**
1476
1494
  * Delete a record by ID
@@ -1485,127 +1503,143 @@ var PrimaryBaseRepository = class {
1485
1503
  */
1486
1504
  async delete(id) {
1487
1505
  this.logger.log(`Deleting record with ID: ${id}`);
1488
- return await this.model.delete({
1489
- where: {
1490
- id
1491
- }
1492
- });
1506
+ const idColumn = this.table.id;
1507
+ const results = await this.db.delete(this.table).where((0, import_drizzle_orm2.eq)(idColumn, id)).returning();
1508
+ return results[0];
1493
1509
  }
1494
1510
  /**
1495
1511
  * Delete multiple records
1496
1512
  *
1497
- * @param where - The where clause to match records
1513
+ * @param where - SQL condition to match records
1498
1514
  * @returns Promise resolving to the count of deleted records
1499
1515
  *
1500
1516
  * @example
1501
1517
  * ```typescript
1502
- * const result = await userRepository.deleteMany({
1503
- * status: 'INACTIVE',
1504
- * createdAt: { lt: new Date('2020-01-01') }
1505
- * });
1518
+ * import { lt } from 'drizzle-orm';
1519
+ *
1520
+ * const result = await userRepository.deleteMany(
1521
+ * lt(users.createdAt, new Date('2020-01-01'))
1522
+ * );
1506
1523
  * console.log(`Deleted ${result.count} users`);
1507
1524
  * ```
1508
1525
  */
1509
1526
  async deleteMany(where) {
1510
1527
  this.logger.log("Deleting multiple records");
1511
- return await this.model.deleteMany({
1512
- where
1513
- });
1528
+ const result = await this.db.delete(this.table).where(where);
1529
+ return {
1530
+ count: result.rowCount ?? 0
1531
+ };
1514
1532
  }
1515
1533
  /**
1516
1534
  * Count records
1517
1535
  *
1518
- * @param where - Optional where clause to filter records
1536
+ * @param where - Optional SQL condition to filter records
1519
1537
  * @returns Promise resolving to the count of records
1520
1538
  *
1521
1539
  * @example
1522
1540
  * ```typescript
1541
+ * import { eq } from 'drizzle-orm';
1542
+ *
1523
1543
  * // Count all users
1524
1544
  * const total = await userRepository.count();
1525
1545
  *
1526
1546
  * // Count active users
1527
- * const activeCount = await userRepository.count({ status: 'ACTIVE' });
1547
+ * const activeCount = await userRepository.count(
1548
+ * eq(users.accountStatus, 'ACTIVE')
1549
+ * );
1528
1550
  * ```
1529
1551
  */
1530
1552
  async count(where) {
1531
1553
  this.logger.debug("Counting records");
1532
- return await this.model.count({
1533
- where
1534
- });
1554
+ let query = this.db.select({
1555
+ count: import_drizzle_orm2.sql`count(*)::int`
1556
+ }).from(this.table).$dynamic();
1557
+ if (where) {
1558
+ query = query.where(where);
1559
+ }
1560
+ const results = await query;
1561
+ return results[0].count;
1535
1562
  }
1536
1563
  /**
1537
1564
  * Check if a record exists
1538
1565
  *
1539
- * @param where - The where clause to match records
1566
+ * @param where - SQL condition to match records
1540
1567
  * @returns Promise resolving to true if at least one record exists, false otherwise
1541
1568
  *
1542
1569
  * @example
1543
1570
  * ```typescript
1544
- * const emailExists = await userRepository.exists({
1545
- * email: 'user@example.com'
1546
- * });
1571
+ * import { eq } from 'drizzle-orm';
1572
+ *
1573
+ * const emailExists = await userRepository.exists(
1574
+ * eq(users.email, 'user@example.com')
1575
+ * );
1547
1576
  * ```
1548
1577
  */
1549
1578
  async exists(where) {
1550
- const count = await this.model.count({
1551
- where
1552
- });
1579
+ const count = await this.count(where);
1553
1580
  return count > 0;
1554
1581
  }
1555
1582
  };
1556
1583
 
1557
1584
  // src/database/repositories/tenant-base.repository.ts
1558
1585
  var import_common12 = require("@nestjs/common");
1586
+ var import_drizzle_orm3 = require("drizzle-orm");
1559
1587
  var TenantBaseRepository = class {
1560
1588
  static {
1561
1589
  __name(this, "TenantBaseRepository");
1562
1590
  }
1563
1591
  database;
1592
+ table;
1564
1593
  logger;
1565
- modelGetter;
1566
1594
  /**
1567
- * Lazy getter for Prisma client.
1595
+ * The table name extracted from the Drizzle table at runtime.
1596
+ * Used to access the query API for this repository's table.
1597
+ */
1598
+ tableName;
1599
+ /**
1600
+ * Lazy getter for Drizzle client.
1568
1601
  * Accesses the client from the database service only when needed,
1569
1602
  * avoiding initialization timing issues with NestJS lifecycle.
1570
1603
  */
1571
- get prisma() {
1572
- return this.database.prismaClient;
1604
+ get db() {
1605
+ return this.database.drizzleClient;
1573
1606
  }
1574
1607
  /**
1575
- * Lazy getter for the Prisma model delegate.
1576
- * Returns the specific model (e.g., prisma.product, prisma.order) for this repository.
1608
+ * Model query API for THIS repository's table (Prisma-like syntax)
1609
+ * Scoped to only the table this repository manages
1610
+ *
1611
+ * @example
1612
+ * ```typescript
1613
+ * // Use relational queries with type safety
1614
+ * const product = await this.model.findFirst({
1615
+ * where: eq(products.id, id),
1616
+ * with: { category: true, variants: true }
1617
+ * });
1618
+ * ```
1577
1619
  */
1578
1620
  get model() {
1579
- return this.modelGetter(this.prisma);
1621
+ return this.database.drizzleClient.query[this.tableName];
1580
1622
  }
1581
1623
  /**
1582
1624
  * Create a new repository instance
1583
1625
  *
1584
1626
  * @param database - The tenant database service
1585
- * @param getModel - Function that returns the Prisma model delegate from the client
1627
+ * @param table - The Drizzle table schema object
1586
1628
  *
1587
1629
  * @example
1588
1630
  * ```typescript
1589
- * // Standard usage with full parameter name
1590
- * constructor(database: TenantDatabaseService) {
1591
- * super(database, (prisma) => prisma.product);
1592
- * }
1593
- *
1594
- * // Short syntax
1595
- * constructor(database: TenantDatabaseService) {
1596
- * super(database, (p) => p.product);
1597
- * }
1631
+ * import { products } from '@/db/schema';
1598
1632
  *
1599
- * // Complex model names
1600
1633
  * constructor(database: TenantDatabaseService) {
1601
- * super(database, (p) => p.inventoryItem);
1634
+ * super(database, products);
1602
1635
  * }
1603
1636
  * ```
1604
1637
  */
1605
- constructor(database, getModel) {
1638
+ constructor(database, table) {
1606
1639
  this.database = database;
1640
+ this.table = table;
1641
+ this.tableName = (0, import_drizzle_orm3.getTableName)(table);
1607
1642
  this.logger = new import_common12.Logger(this.constructor.name);
1608
- this.modelGetter = getModel;
1609
1643
  this.logger.debug(`Initialized ${this.constructor.name}`);
1610
1644
  }
1611
1645
  /**
@@ -1625,9 +1659,8 @@ var TenantBaseRepository = class {
1625
1659
  */
1626
1660
  async create(data) {
1627
1661
  this.logger.log("Creating record");
1628
- return await this.model.create({
1629
- data
1630
- });
1662
+ const results = await this.db.insert(this.table).values(data).returning();
1663
+ return results[0];
1631
1664
  }
1632
1665
  /**
1633
1666
  * Find a single record by ID
@@ -1642,59 +1675,65 @@ var TenantBaseRepository = class {
1642
1675
  */
1643
1676
  async findById(id) {
1644
1677
  this.logger.debug(`Finding record by ID: ${id}`);
1645
- return await this.model.findUnique({
1646
- where: {
1647
- id
1648
- }
1649
- });
1678
+ const idColumn = this.table.id;
1679
+ const results = await this.db.select().from(this.table).where((0, import_drizzle_orm3.eq)(idColumn, id)).limit(1);
1680
+ return results[0] ?? null;
1650
1681
  }
1651
1682
  /**
1652
1683
  * Find a single record with custom where clause
1653
1684
  *
1654
- * @param where - The where clause or findUnique args
1685
+ * @param where - SQL condition
1655
1686
  * @returns Promise resolving to the record or null if not found
1656
1687
  *
1657
1688
  * @example
1658
1689
  * ```typescript
1659
- * // Simple where clause
1660
- * const product = await productRepository.findOne({ sku: 'WDG-001' });
1661
- *
1662
- * // With include
1663
- * const product = await productRepository.findOne({
1664
- * where: { sku: 'WDG-001' },
1665
- * include: { category: true }
1666
- * });
1690
+ * import { eq } from 'drizzle-orm';
1691
+ * const product = await productRepository.findOne(eq(products.sku, 'WDG-001'));
1667
1692
  * ```
1668
1693
  */
1669
1694
  async findOne(where) {
1670
1695
  this.logger.debug("Finding record with custom query");
1671
- return await this.model.findUnique(typeof where === "object" && "where" in where ? where : {
1672
- where
1673
- });
1696
+ const results = await this.db.select().from(this.table).where(where).limit(1);
1697
+ return results[0] ?? null;
1674
1698
  }
1675
1699
  /**
1676
1700
  * Find multiple records
1677
1701
  *
1678
- * @param args - Prisma findMany arguments (where, orderBy, take, skip, etc.)
1702
+ * @param options - Query options (where, orderBy, limit, offset)
1679
1703
  * @returns Promise resolving to an array of records
1680
1704
  *
1681
1705
  * @example
1682
1706
  * ```typescript
1707
+ * import { eq, desc } from 'drizzle-orm';
1708
+ *
1683
1709
  * // Find all products
1684
1710
  * const products = await productRepository.findMany();
1685
1711
  *
1686
1712
  * // Find with filtering and pagination
1687
1713
  * const products = await productRepository.findMany({
1688
- * where: { status: 'ACTIVE' },
1689
- * orderBy: { createdAt: 'desc' },
1690
- * take: 10,
1691
- * skip: 0
1714
+ * where: eq(products.status, 'ACTIVE'),
1715
+ * orderBy: desc(products.createdAt),
1716
+ * limit: 10,
1717
+ * offset: 0
1692
1718
  * });
1693
1719
  * ```
1694
1720
  */
1695
- async findMany(args) {
1721
+ async findMany(options) {
1696
1722
  this.logger.debug("Finding multiple records");
1697
- return await this.model.findMany(args);
1723
+ let query = this.db.select().from(this.table).$dynamic();
1724
+ if (options?.where) {
1725
+ query = query.where(options.where);
1726
+ }
1727
+ if (options?.orderBy) {
1728
+ query = query.orderBy(options.orderBy);
1729
+ }
1730
+ if (options?.limit) {
1731
+ query = query.limit(options.limit);
1732
+ }
1733
+ if (options?.offset) {
1734
+ query = query.offset(options.offset);
1735
+ }
1736
+ return await query;
1698
1737
  }
1699
1738
  /**
1700
1739
  * Update a record by ID
@@ -1712,24 +1751,23 @@ var TenantBaseRepository = class {
1712
1751
  */
1713
1752
  async update(id, data) {
1714
1753
  this.logger.log(`Updating record with ID: ${id}`);
1715
- return await this.model.update({
1716
- where: {
1717
- id
1718
- },
1719
- data
1720
- });
1754
+ const idColumn = this.table.id;
1755
+ const results = await this.db.update(this.table).set(data).where((0, import_drizzle_orm3.eq)(idColumn, id)).returning();
1756
+ return results[0];
1721
1757
  }
1722
1758
  /**
1723
1759
  * Update multiple records
1724
1760
  *
1725
- * @param where - The where clause to match records
1761
+ * @param where - SQL condition to match records
1726
1762
  * @param data - The data to update
1727
1763
  * @returns Promise resolving to the count of updated records
1728
1764
  *
1729
1765
  * @example
1730
1766
  * ```typescript
1767
+ * import { eq } from 'drizzle-orm';
1768
+ *
1731
1769
  * const result = await productRepository.updateMany(
1732
- * { status: 'PENDING' },
1770
+ * eq(products.status, 'PENDING'),
1733
1771
  * { status: 'ACTIVE' }
1734
1772
  * );
1735
1773
  * console.log(`Updated ${result.count} products`);
@@ -1737,10 +1775,10 @@ var TenantBaseRepository = class {
1737
1775
  */
1738
1776
  async updateMany(where, data) {
1739
1777
  this.logger.log("Updating multiple records");
1740
- return await this.model.updateMany({
1741
- where,
1742
- data
1743
- });
1778
+ const result = await this.db.update(this.table).set(data).where(where);
1779
+ return {
1780
+ count: result.rowCount ?? 0
1781
+ };
1744
1782
  }
1745
1783
  /**
1746
1784
  * Delete a record by ID
@@ -1755,71 +1793,80 @@ var TenantBaseRepository = class {
1755
1793
  */
1756
1794
  async delete(id) {
1757
1795
  this.logger.log(`Deleting record with ID: ${id}`);
1758
- return await this.model.delete({
1759
- where: {
1760
- id
1761
- }
1762
- });
1796
+ const idColumn = this.table.id;
1797
+ const results = await this.db.delete(this.table).where((0, import_drizzle_orm3.eq)(idColumn, id)).returning();
1798
+ return results[0];
1763
1799
  }
1764
1800
  /**
1765
1801
  * Delete multiple records
1766
1802
  *
1767
- * @param where - The where clause to match records
1803
+ * @param where - SQL condition to match records
1768
1804
  * @returns Promise resolving to the count of deleted records
1769
1805
  *
1770
1806
  * @example
1771
1807
  * ```typescript
1772
- * const result = await productRepository.deleteMany({
1773
- * status: 'INACTIVE',
1774
- * createdAt: { lt: new Date('2020-01-01') }
1775
- * });
1808
+ * import { lt } from 'drizzle-orm';
1809
+ *
1810
+ * const result = await productRepository.deleteMany(
1811
+ * lt(products.createdAt, new Date('2020-01-01'))
1812
+ * );
1776
1813
  * console.log(`Deleted ${result.count} products`);
1777
1814
  * ```
1778
1815
  */
1779
1816
  async deleteMany(where) {
1780
1817
  this.logger.log("Deleting multiple records");
1781
- return await this.model.deleteMany({
1782
- where
1783
- });
1818
+ const result = await this.db.delete(this.table).where(where);
1819
+ return {
1820
+ count: result.rowCount ?? 0
1821
+ };
1784
1822
  }
1785
1823
  /**
1786
1824
  * Count records
1787
1825
  *
1788
- * @param where - Optional where clause to filter records
1826
+ * @param where - Optional SQL condition to filter records
1789
1827
  * @returns Promise resolving to the count of records
1790
1828
  *
1791
1829
  * @example
1792
1830
  * ```typescript
1831
+ * import { eq } from 'drizzle-orm';
1832
+ *
1793
1833
  * // Count all products
1794
1834
  * const total = await productRepository.count();
1795
1835
  *
1796
1836
  * // Count active products
1797
- * const activeCount = await productRepository.count({ status: 'ACTIVE' });
1837
+ * const activeCount = await productRepository.count(
1838
+ * eq(products.status, 'ACTIVE')
1839
+ * );
1798
1840
  * ```
1799
1841
  */
1800
1842
  async count(where) {
1801
1843
  this.logger.debug("Counting records");
1802
- return await this.model.count({
1803
- where
1804
- });
1844
+ let query = this.db.select({
1845
+ count: import_drizzle_orm3.sql`count(*)::int`
1846
+ }).from(this.table).$dynamic();
1847
+ if (where) {
1848
+ query = query.where(where);
1849
+ }
1850
+ const results = await query;
1851
+ return results[0].count;
1805
1852
  }
1806
1853
  /**
1807
1854
  * Check if a record exists
1808
1855
  *
1809
- * @param where - The where clause to match records
1856
+ * @param where - SQL condition to match records
1810
1857
  * @returns Promise resolving to true if at least one record exists, false otherwise
1811
1858
  *
1812
1859
  * @example
1813
1860
  * ```typescript
1814
- * const skuExists = await productRepository.exists({
1815
- * sku: 'WDG-001'
1816
- * });
1861
+ * import { eq } from 'drizzle-orm';
1862
+ *
1863
+ * const skuExists = await productRepository.exists(
1864
+ * eq(products.sku, 'WDG-001')
1865
+ * );
1817
1866
  * ```
1818
1867
  */
1819
1868
  async exists(where) {
1820
- const count = await this.model.count({
1821
- where
1822
- });
1869
+ const count = await this.count(where);
1823
1870
  return count > 0;
1824
1871
  }
1825
1872
  };
@@ -1976,15 +2023,16 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
1976
2023
  const exceptionResponse = exception.getResponse();
1977
2024
  if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
1978
2025
  const responseObj = exceptionResponse;
1979
- if (responseObj.errors && Array.isArray(responseObj.errors)) {
2026
+ if ("errors" in responseObj && Array.isArray(responseObj.errors)) {
1980
2027
  errors = responseObj.errors;
1981
- detail = responseObj.detail || exception.message;
1982
- } else if (responseObj.message && Array.isArray(responseObj.message)) {
2028
+ detail = ("detail" in responseObj ? responseObj.detail : void 0) || exception.message;
2029
+ } else if ("message" in responseObj && Array.isArray(responseObj.message)) {
1983
2030
  errors = responseObj.message.map((msg) => {
1984
- if (typeof msg === "object" && msg.property && msg.constraints) {
2031
+ if (typeof msg === "object" && "property" in msg && "constraints" in msg) {
2032
+ const constraintValues = Object.values(msg.constraints);
1985
2033
  return {
1986
2034
  field: msg.property,
1987
- message: Object.values(msg.constraints)[0]
2035
+ message: constraintValues[0] ?? "Validation failed"
1988
2036
  };
1989
2037
  }
1990
2038
  return {
@@ -1992,13 +2040,14 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
1992
2040
  };
1993
2041
  });
1994
2042
  detail = "Validation failed";
1995
- } else if (responseObj.message) {
2043
+ } else if ("message" in responseObj) {
2044
+ const message = responseObj.message;
1996
2045
  errors = [
1997
2046
  {
1998
- message: Array.isArray(responseObj.message) ? responseObj.message.join(", ") : responseObj.message
2047
+ message: Array.isArray(message) ? message.join(", ") : message
1999
2048
  }
2000
2049
  ];
2001
- detail = responseObj.error || exception.message;
2050
+ detail = ("error" in responseObj ? responseObj.error : void 0) || exception.message;
2002
2051
  }
2003
2052
  } else if (typeof exceptionResponse === "string") {
2004
2053
  errors = [
@@ -2009,7 +2058,9 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
2009
2058
  detail = exceptionResponse;
2010
2059
  }
2011
2060
  } else {
2012
- this.logger.error("Unexpected error:", exception);
2061
+ const errorMessage = exception instanceof Error ? exception.message : "Unknown error";
2062
+ const stack = exception instanceof Error ? exception.stack : void 0;
2063
+ this.logger.error(`Unexpected error: ${errorMessage}`, stack);
2013
2064
  errors = [
2014
2065
  {
2015
2066
  message: "An unexpected error occurred"
@@ -2412,6 +2463,885 @@ var BadGatewayException = class extends BaseFieldException {
2412
2463
  }
2413
2464
  }
2414
2465
  };
2466
+
2467
+ // src/logger/logger.module.ts
2468
+ var import_common41 = require("@nestjs/common");
2469
+
2470
+ // src/logger/services/logger.service.ts
2471
+ var import_common38 = require("@nestjs/common");
2472
+ var import_winston = require("winston");
2473
+ var import_winston_daily_rotate_file = __toESM(require("winston-daily-rotate-file"), 1);
2474
+
2475
+ // src/logger/utils/index.ts
2476
+ var import_node_async_hooks = require("async_hooks");
2477
+ var import_node_crypto = require("crypto");
2478
+ var correlationStorage = new import_node_async_hooks.AsyncLocalStorage();
2479
+ function getCorrelationContext() {
2480
+ return correlationStorage.getStore();
2481
+ }
2482
+ __name(getCorrelationContext, "getCorrelationContext");
2483
+ function runWithCorrelationContext(context, callback) {
2484
+ return correlationStorage.run(context, callback);
2485
+ }
2486
+ __name(runWithCorrelationContext, "runWithCorrelationContext");
2487
+ function updateCorrelationContext(updates) {
2488
+ const context = correlationStorage.getStore();
2489
+ if (context) {
2490
+ Object.assign(context, updates);
2491
+ }
2492
+ }
2493
+ __name(updateCorrelationContext, "updateCorrelationContext");
2494
+ var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
2495
+ function generateCorrelationId() {
2496
+ return (0, import_node_crypto.randomUUID)();
2497
+ }
2498
+ __name(generateCorrelationId, "generateCorrelationId");
2499
+ function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
2500
+ if (typeof reply.header === "function") {
2501
+ reply.header(headerName, correlationId);
2502
+ } else if (reply.raw && typeof reply.raw.setHeader === "function") {
2503
+ reply.raw.setHeader(headerName, correlationId);
2504
+ }
2505
+ }
2506
+ __name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
2507
+
2508
+ // src/logger/services/logger.service.ts
2509
+ function _ts_decorate14(decorators, target, key, desc) {
2510
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2511
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2512
+ 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;
2513
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2514
+ }
2515
+ __name(_ts_decorate14, "_ts_decorate");
2516
+ function _ts_metadata8(k, v) {
2517
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2518
+ }
2519
+ __name(_ts_metadata8, "_ts_metadata");
2520
+ function _ts_param4(paramIndex, decorator) {
2521
+ return function(target, key) {
2522
+ decorator(target, key, paramIndex);
2523
+ };
2524
+ }
2525
+ __name(_ts_param4, "_ts_param");
2526
+ var LoggerService2 = class _LoggerService {
2527
+ static {
2528
+ __name(this, "LoggerService");
2529
+ }
2530
+ defaultLogger;
2531
+ activeLogger;
2532
+ options;
2533
+ context;
2534
+ constructor(options = {}, defaultLogger) {
2535
+ this.defaultLogger = defaultLogger;
2536
+ this.options = options;
2537
+ const provider = options.provider ?? "winston";
2538
+ if (provider === "default") {
2539
+ if (!this.defaultLogger) {
2540
+ throw new Error("LoggerService: Default Logger not provided");
2541
+ }
2542
+ this.activeLogger = this.defaultLogger;
2543
+ } else {
2544
+ this.activeLogger = this.createWinstonLogger(options);
2545
+ }
2546
+ }
2547
+ /**
2548
+ * Creates a Winston logger instance with inline configuration.
2549
+ * Consolidates winston-config.factory.ts logic.
2550
+ */
2551
+ createWinstonLogger(opts) {
2552
+ const level = opts.level ?? "debug";
2553
+ const logFormat = opts.format ?? "text";
2554
+ const baseFormatters = [
2555
+ import_winston.format.timestamp({
2556
+ format: "YYYY-MM-DDTHH:mm:ss.SSSZ"
2557
+ }),
2558
+ import_winston.format.errors({
2559
+ stack: true
2560
+ })
2561
+ ];
2562
+ const consoleTransport = logFormat === "json" ? new import_winston.transports.Console({
2563
+ level,
2564
+ format: import_winston.format.combine(...baseFormatters, import_winston.format.json())
2565
+ }) : new import_winston.transports.Console({
2566
+ level,
2567
+ format: import_winston.format.combine(...baseFormatters, import_winston.format.printf((info) => {
2568
+ const { timestamp, level: level2, message, context, correlationId, trace } = info;
2569
+ const parts = [
2570
+ timestamp,
2571
+ level2.toUpperCase().padEnd(7),
2572
+ correlationId ? `[${correlationId.toString().slice(-6)}]` : "",
2573
+ context ? `[${context}]` : "",
2574
+ message
2575
+ ].filter(Boolean);
2576
+ let output = parts.join(" ");
2577
+ if (trace) {
2578
+ output += "\n" + trace;
2579
+ }
2580
+ return output;
2581
+ }), import_winston.format.colorize({
2582
+ all: true
2583
+ }))
2584
+ });
2585
+ const winstonTransports = [
2586
+ consoleTransport
2587
+ ];
2588
+ if (opts.enableFileLogger) {
2589
+ const filePath = opts.filePath ?? "./logs";
2590
+ const maxFiles = opts.maxFiles ?? "14d";
2591
+ winstonTransports.push(new import_winston_daily_rotate_file.default({
2592
+ level,
2593
+ filename: `${filePath}/%DATE%-combined.log`,
2594
+ datePattern: "YYYY-MM-DD",
2595
+ maxSize: "20m",
2596
+ maxFiles,
2597
+ format: import_winston.format.combine(import_winston.format.timestamp(), import_winston.format.json())
2598
+ }), new import_winston_daily_rotate_file.default({
2599
+ level: "error",
2600
+ filename: `${filePath}/%DATE%-error.log`,
2601
+ datePattern: "YYYY-MM-DD",
2602
+ maxSize: "20m",
2603
+ maxFiles,
2604
+ format: import_winston.format.combine(import_winston.format.timestamp(), import_winston.format.json())
2605
+ }));
2606
+ }
2607
+ const config = {
2608
+ level,
2609
+ transports: winstonTransports,
2610
+ exitOnError: false
2611
+ };
2612
+ if (opts.defaultMeta || opts.appName) {
2613
+ config.defaultMeta = {
2614
+ ...opts.defaultMeta,
2615
+ appName: opts.appName,
2616
+ environment: opts.environment
2617
+ };
2618
+ }
2619
+ return (0, import_winston.createLogger)(config);
2620
+ }
2621
+ // NestJS LoggerService interface methods
2622
+ log(message, context) {
2623
+ this._log("log", message, context);
2624
+ }
2625
+ error(message, trace, context) {
2626
+ this._log("error", message, context, trace);
2627
+ }
2628
+ warn(message, context) {
2629
+ this._log("warn", message, context);
2630
+ }
2631
+ debug(message, context) {
2632
+ this._log("debug", message, context);
2633
+ }
2634
+ verbose(message, context) {
2635
+ this._log("verbose", message, context);
2636
+ }
2637
+ setContext(context) {
2638
+ this.context = context;
2639
+ }
2640
+ /**
2641
+ * Unified internal logging method that handles both Winston and NestJS Logger.
2642
+ */
2643
+ _log(level, message, context, trace) {
2644
+ const ctx = context ?? this.context;
2645
+ if ("format" in this.activeLogger && "transports" in this.activeLogger) {
2646
+ const winstonLogger = this.activeLogger;
2647
+ const winstonLevel = level === "log" ? "info" : level;
2648
+ const formattedMessage = this.formatMessage(message);
2649
+ const metadata = this.enrichMetadata({}, ctx, trace);
2650
+ winstonLogger.log({
2651
+ level: winstonLevel,
2652
+ message: formattedMessage,
2653
+ ...metadata
2654
+ });
2655
+ } else {
2656
+ const nestLogger = this.activeLogger;
2657
+ if (level === "error" && trace) {
2658
+ ctx ? nestLogger.error(message, trace, ctx) : nestLogger.error(message, trace);
2659
+ } else if (level === "log") {
2660
+ ctx ? nestLogger.log(message, ctx) : nestLogger.log(message);
2661
+ } else if (level === "warn") {
2662
+ ctx ? nestLogger.warn(message, ctx) : nestLogger.warn(message);
2663
+ } else if (level === "debug" && nestLogger.debug) {
2664
+ ctx ? nestLogger.debug(message, ctx) : nestLogger.debug(message);
2665
+ } else if (level === "verbose" && nestLogger.verbose) {
2666
+ ctx ? nestLogger.verbose(message, ctx) : nestLogger.verbose(message);
2667
+ }
2668
+ }
2669
+ }
2670
+ /**
2671
+ * Logs with custom metadata (Winston only).
2672
+ */
2673
+ logWithMetadata(level, message, metadata, context) {
2674
+ const ctx = context ?? this.context;
2675
+ if ("format" in this.activeLogger && "transports" in this.activeLogger) {
2676
+ const winstonLogger = this.activeLogger;
2677
+ const winstonLevel = level === "log" ? "info" : level;
2678
+ winstonLogger.log({
2679
+ level: winstonLevel,
2680
+ message: this.formatMessage(message),
2681
+ ...metadata
2682
+ });
2683
+ } else {
2684
+ const messageWithMeta = metadata ? `${message} ${JSON.stringify(metadata)}` : message;
2685
+ this[level](messageWithMeta, ctx);
2686
+ }
2687
+ }
2688
+ formatMessage(message) {
2689
+ if (message instanceof Error) return message.message;
2690
+ if (typeof message === "object" && message !== null) {
2691
+ try {
2692
+ return JSON.stringify(message);
2693
+ } catch {
2694
+ return String(message);
2695
+ }
2696
+ }
2697
+ return String(message);
2698
+ }
2699
+ /**
2700
+ * Enriches metadata with correlation context from AsyncLocalStorage.
2701
+ * Inline from winston-logger.service.ts
2702
+ */
2703
+ enrichMetadata(metadata = {}, context, trace) {
2704
+ const enriched = {
2705
+ ...metadata
2706
+ };
2707
+ if (context) enriched.context = context;
2708
+ const correlationContext = getCorrelationContext();
2709
+ if (correlationContext) {
2710
+ if (correlationContext.correlationId) enriched.correlationId = correlationContext.correlationId;
2711
+ for (const [key, value] of Object.entries(correlationContext)) {
2712
+ if (key !== "correlationId") {
2713
+ enriched[key] = value;
2714
+ }
2715
+ }
2716
+ }
2717
+ if (trace) enriched.trace = trace;
2718
+ return enriched;
2719
+ }
2720
+ child(context) {
2721
+ const childLogger = new _LoggerService(this.options, this.defaultLogger);
2722
+ childLogger.setContext(context);
2723
+ return childLogger;
2724
+ }
2725
+ };
2726
+ LoggerService2 = _ts_decorate14([
2727
+ (0, import_common38.Injectable)(),
2728
+ _ts_param4(0, (0, import_common38.Optional)()),
2729
+ _ts_param4(1, (0, import_common38.Optional)()),
2730
+ _ts_metadata8("design:type", Function),
2731
+ _ts_metadata8("design:paramtypes", [
2732
+ typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
2733
+ typeof import_common38.Logger === "undefined" ? Object : import_common38.Logger
2734
+ ])
2735
+ ], LoggerService2);
2736
+
2737
+ // src/logger/middleware/correlation-id.middleware.ts
2738
+ var import_common39 = require("@nestjs/common");
2739
+ function _ts_decorate15(decorators, target, key, desc) {
2740
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2741
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2742
+ 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;
2743
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2744
+ }
2745
+ __name(_ts_decorate15, "_ts_decorate");
2746
+ function _ts_metadata9(k, v) {
2747
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2748
+ }
2749
+ __name(_ts_metadata9, "_ts_metadata");
2750
+ var CorrelationIdMiddleware = class {
2751
+ static {
2752
+ __name(this, "CorrelationIdMiddleware");
2753
+ }
2754
+ includeInResponse;
2755
+ responseHeader;
2756
+ constructor(options = {}) {
2757
+ this.includeInResponse = options.includeInResponse ?? true;
2758
+ this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
2759
+ }
2760
+ /**
2761
+ * Middleware handler for processing requests.
2762
+ */
2763
+ use(req, reply, next) {
2764
+ const correlationId = generateCorrelationId();
2765
+ if (this.includeInResponse) {
2766
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2767
+ }
2768
+ runWithCorrelationContext({
2769
+ correlationId
2770
+ }, () => {
2771
+ next();
2772
+ });
2773
+ }
2774
+ /**
2775
+ * Fastify hook handler for onRequest.
2776
+ * This is an async function that returns a Promise, ensuring the AsyncLocalStorage
2777
+ * context persists throughout the entire request lifecycle.
2778
+ */
2779
+ async onRequest(req, reply) {
2780
+ const correlationId = generateCorrelationId();
2781
+ if (this.includeInResponse) {
2782
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2783
+ }
2784
+ const store = correlationStorage.getStore();
2785
+ if (!store) {
2786
+ correlationStorage.enterWith({
2787
+ correlationId
2788
+ });
2789
+ }
2790
+ }
2791
+ };
2792
+ CorrelationIdMiddleware = _ts_decorate15([
2793
+ (0, import_common39.Injectable)(),
2794
+ _ts_metadata9("design:type", Function),
2795
+ _ts_metadata9("design:paramtypes", [
2796
+ typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
2797
+ ])
2798
+ ], CorrelationIdMiddleware);
2799
+
2800
+ // src/logger/interceptors/http-logger.interceptor.ts
2801
+ var import_common40 = require("@nestjs/common");
2802
+ var import_operators2 = require("rxjs/operators");
2803
+ function _ts_decorate16(decorators, target, key, desc) {
2804
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2805
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2806
+ 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;
2807
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2808
+ }
2809
+ __name(_ts_decorate16, "_ts_decorate");
2810
+ function _ts_metadata10(k, v) {
2811
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2812
+ }
2813
+ __name(_ts_metadata10, "_ts_metadata");
2814
+ function _ts_param5(paramIndex, decorator) {
2815
+ return function(target, key) {
2816
+ decorator(target, key, paramIndex);
2817
+ };
2818
+ }
2819
+ __name(_ts_param5, "_ts_param");
2820
+ var HttpLoggerInterceptor = class {
2821
+ static {
2822
+ __name(this, "HttpLoggerInterceptor");
2823
+ }
2824
+ logger;
2825
+ enableRequestLog;
2826
+ enableResponseLog;
2827
+ slowRequestThreshold;
2828
+ constructor(logger, options) {
2829
+ this.logger = logger;
2830
+ this.enableRequestLog = options?.enableRequestLog ?? true;
2831
+ this.enableResponseLog = options?.enableResponseLog ?? true;
2832
+ this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
2833
+ }
2834
+ intercept(context, next) {
2835
+ if (context.getType() !== "http") {
2836
+ return next.handle();
2837
+ }
2838
+ const httpContext = context.switchToHttp();
2839
+ const request = httpContext.getRequest();
2840
+ const response = httpContext.getResponse();
2841
+ const startTime = Date.now();
2842
+ if (this.enableRequestLog) {
2843
+ this.logRequest(request);
2844
+ }
2845
+ return next.handle().pipe((0, import_operators2.tap)(() => {
2846
+ if (this.enableResponseLog) {
2847
+ const duration = Date.now() - startTime;
2848
+ this.logResponse(request, response, duration);
2849
+ }
2850
+ }), (0, import_operators2.catchError)((error) => {
2851
+ const duration = Date.now() - startTime;
2852
+ this.logError(request, response, duration, error);
2853
+ throw error;
2854
+ }));
2855
+ }
2856
+ logRequest(request) {
2857
+ try {
2858
+ const correlationContext = getCorrelationContext();
2859
+ const metadata = {
2860
+ type: "http_request",
2861
+ method: request.method,
2862
+ url: request.url,
2863
+ correlationId: correlationContext?.correlationId,
2864
+ ip: request.ip,
2865
+ userAgent: request.headers["user-agent"]
2866
+ };
2867
+ this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
2868
+ } catch (error) {
2869
+ this.logger.error("Failed to log HTTP request", error.stack);
2870
+ }
2871
+ }
2872
+ logResponse(request, response, duration) {
2873
+ try {
2874
+ const correlationContext = getCorrelationContext();
2875
+ const statusCode = response.statusCode;
2876
+ const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
2877
+ const metadata = {
2878
+ type: "http_response",
2879
+ method: request.method,
2880
+ url: request.url,
2881
+ statusCode,
2882
+ duration,
2883
+ correlationId: correlationContext?.correlationId
2884
+ };
2885
+ if (duration > this.slowRequestThreshold) {
2886
+ metadata.slowRequest = true;
2887
+ }
2888
+ const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
2889
+ this.logger.logWithMetadata(logLevel, message, metadata);
2890
+ } catch (error) {
2891
+ this.logger.error("Failed to log HTTP response", error.stack);
2892
+ }
2893
+ }
2894
+ logError(request, response, duration, error) {
2895
+ try {
2896
+ const correlationContext = getCorrelationContext();
2897
+ const statusCode = response.statusCode || 500;
2898
+ const metadata = {
2899
+ type: "http_error",
2900
+ method: request.method,
2901
+ url: request.url,
2902
+ statusCode,
2903
+ duration,
2904
+ correlationId: correlationContext?.correlationId,
2905
+ errorName: error?.name || "Error",
2906
+ errorMessage: error?.message || "Unknown error"
2907
+ };
2908
+ if (error?.stack) {
2909
+ metadata.trace = error.stack;
2910
+ }
2911
+ if (error?.response) {
2912
+ metadata.errorDetails = error.response;
2913
+ }
2914
+ const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
2915
+ this.logger.logWithMetadata("error", message, metadata);
2916
+ } catch (loggingError) {
2917
+ this.logger.error("Failed to log HTTP error", loggingError.stack);
2918
+ }
2919
+ }
2920
+ };
2921
+ HttpLoggerInterceptor = _ts_decorate16([
2922
+ (0, import_common40.Injectable)(),
2923
+ _ts_param5(1, (0, import_common40.Optional)()),
2924
+ _ts_metadata10("design:type", Function),
2925
+ _ts_metadata10("design:paramtypes", [
2926
+ typeof LoggerService === "undefined" ? Object : LoggerService,
2927
+ typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
2928
+ ])
2929
+ ], HttpLoggerInterceptor);
2930
+
2931
+ // src/logger/logger.module.ts
2932
+ function _ts_decorate17(decorators, target, key, desc) {
2933
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2934
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2935
+ 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;
2936
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2937
+ }
2938
+ __name(_ts_decorate17, "_ts_decorate");
2939
+ var LOGGER_MODULE_OPTIONS = Symbol("LOGGER_MODULE_OPTIONS");
2940
+ var DEFAULT_LOGGER_OPTIONS = {
2941
+ provider: "winston",
2942
+ enableCorrelationId: true,
2943
+ enableHttpLogger: true,
2944
+ filePath: "./logs",
2945
+ maxFiles: "14d"
2946
+ };
2947
+ var ENVIRONMENT_PRESETS = {
2948
+ /**
2949
+ * Development preset - maximum verbosity for local development
2950
+ */
2951
+ development: {
2952
+ provider: "winston",
2953
+ level: "debug",
2954
+ format: "text",
2955
+ enableFileLogger: false,
2956
+ enableCorrelationId: true,
2957
+ enableHttpLogger: true,
2958
+ httpLogger: {
2959
+ enableRequestLog: true,
2960
+ enableResponseLog: true,
2961
+ slowRequestThreshold: 1e3
2962
+ }
2963
+ },
2964
+ /**
2965
+ * Staging preset - moderate verbosity with file logging
2966
+ */
2967
+ staging: {
2968
+ provider: "winston",
2969
+ level: "log",
2970
+ format: "json",
2971
+ enableFileLogger: true,
2972
+ enableCorrelationId: true,
2973
+ enableHttpLogger: true,
2974
+ httpLogger: {
2975
+ enableRequestLog: true,
2976
+ enableResponseLog: true,
2977
+ slowRequestThreshold: 3e3
2978
+ }
2979
+ },
2980
+ /**
2981
+ * Production preset - minimal verbosity with all safety features enabled
2982
+ */
2983
+ production: {
2984
+ provider: "winston",
2985
+ level: "warn",
2986
+ format: "json",
2987
+ enableFileLogger: true,
2988
+ enableCorrelationId: true,
2989
+ enableHttpLogger: true,
2990
+ httpLogger: {
2991
+ enableRequestLog: false,
2992
+ enableResponseLog: true,
2993
+ slowRequestThreshold: 5e3
2994
+ }
2995
+ },
2996
+ /**
2997
+ * Test preset - errors only, minimal features for faster test execution
2998
+ */
2999
+ test: {
3000
+ provider: "winston",
3001
+ level: "error",
3002
+ format: "json",
3003
+ enableFileLogger: false,
3004
+ enableCorrelationId: false,
3005
+ enableHttpLogger: false
3006
+ }
3007
+ };
3008
+ function mergeWithDefaults(options = {}) {
3009
+ const preset = options.environment ? ENVIRONMENT_PRESETS[options.environment] ?? ENVIRONMENT_PRESETS.development : ENVIRONMENT_PRESETS.development;
3010
+ const filteredOptions = Object.fromEntries(Object.entries(options).filter(([_, value]) => value !== void 0));
3011
+ if (filteredOptions.httpLogger && preset?.httpLogger) {
3012
+ filteredOptions.httpLogger = {
3013
+ ...preset.httpLogger,
3014
+ ...Object.fromEntries(Object.entries(filteredOptions.httpLogger).filter(([_, value]) => value !== void 0))
3015
+ };
3016
+ }
3017
+ const merged = {
3018
+ ...DEFAULT_LOGGER_OPTIONS,
3019
+ ...preset,
3020
+ ...filteredOptions
3021
+ };
3022
+ return merged;
3023
+ }
3024
+ __name(mergeWithDefaults, "mergeWithDefaults");
3025
+ function createDefaultLoggerProvider(options) {
3026
+ return {
3027
+ provide: import_common41.Logger,
3028
+ useFactory: /* @__PURE__ */ __name(() => {
3029
+ const logger = new import_common41.Logger();
3030
+ if (options.level && typeof logger.setLogLevels === "function") {
3031
+ const levels = getLevelsUpTo(options.level);
3032
+ logger.setLogLevels(levels);
3033
+ }
3034
+ return logger;
3035
+ }, "useFactory")
3036
+ };
3037
+ }
3038
+ __name(createDefaultLoggerProvider, "createDefaultLoggerProvider");
3039
+ function createLoggerProviders(options = {}) {
3040
+ const mergedOptions = mergeWithDefaults(options);
3041
+ const providers = [
3042
+ // Options provider
3043
+ {
3044
+ provide: LOGGER_MODULE_OPTIONS,
3045
+ useValue: mergedOptions
3046
+ }
3047
+ ];
3048
+ if (mergedOptions.provider === "default") {
3049
+ providers.push(createDefaultLoggerProvider(mergedOptions));
3050
+ }
3051
+ providers.push({
3052
+ provide: LoggerService2,
3053
+ useFactory: /* @__PURE__ */ __name((opts, defaultLogger) => {
3054
+ return new LoggerService2(opts, defaultLogger);
3055
+ }, "useFactory"),
3056
+ inject: [
3057
+ LOGGER_MODULE_OPTIONS,
3058
+ {
3059
+ token: import_common41.Logger,
3060
+ optional: true
3061
+ }
3062
+ ]
3063
+ });
3064
+ providers.push({
3065
+ provide: CorrelationIdMiddleware,
3066
+ useFactory: /* @__PURE__ */ __name(() => {
3067
+ return new CorrelationIdMiddleware({
3068
+ includeInResponse: true,
3069
+ responseHeader: "x-correlation-id"
3070
+ });
3071
+ }, "useFactory")
3072
+ });
3073
+ providers.push({
3074
+ provide: HttpLoggerInterceptor,
3075
+ useFactory: /* @__PURE__ */ __name((logger, opts) => {
3076
+ const httpLoggerOptions = opts.httpLogger ?? {
3077
+ enableRequestLog: opts.enableHttpLogger,
3078
+ enableResponseLog: opts.enableHttpLogger
3079
+ };
3080
+ return new HttpLoggerInterceptor(logger, httpLoggerOptions);
3081
+ }, "useFactory"),
3082
+ inject: [
3083
+ LoggerService2,
3084
+ LOGGER_MODULE_OPTIONS
3085
+ ]
3086
+ });
3087
+ return providers;
3088
+ }
3089
+ __name(createLoggerProviders, "createLoggerProviders");
3090
+ function getLevelsUpTo(level) {
3091
+ const allLevels = [
3092
+ "error",
3093
+ "warn",
3094
+ "log",
3095
+ "debug",
3096
+ "verbose"
3097
+ ];
3098
+ const isValidLevel = /* @__PURE__ */ __name((l) => allLevels.includes(l), "isValidLevel");
3099
+ if (!isValidLevel(level)) {
3100
+ return [
3101
+ "error",
3102
+ "warn",
3103
+ "log"
3104
+ ];
3105
+ }
3106
+ const levelIndex = allLevels.indexOf(level);
3107
+ return allLevels.slice(0, levelIndex + 1);
3108
+ }
3109
+ __name(getLevelsUpTo, "getLevelsUpTo");
3110
+ var LoggerModule = class _LoggerModule {
3111
+ static {
3112
+ __name(this, "LoggerModule");
3113
+ }
3114
+ /**
3115
+ * Configures the logger module with static options.
3116
+ *
3117
+ * Users must explicitly pass `environment` to select a preset.
3118
+ * All preset values can be overridden by passing explicit options.
3119
+ *
3120
+ * @param options - Logger configuration options
3121
+ * @returns Dynamic module configuration
3122
+ *
3123
+ * @example
3124
+ * ```typescript
3125
+ * // Production preset with app name
3126
+ * LoggerModule.forRoot({
3127
+ * environment: 'production',
3128
+ * appName: 'my-service'
3129
+ * })
3130
+ *
3131
+ * // Development preset with custom level
3132
+ * LoggerModule.forRoot({
3133
+ * environment: 'development',
3134
+ * level: 'verbose',
3135
+ * enableFileLogger: true
3136
+ * })
3137
+ *
3138
+ * // Use default NestJS logger
3139
+ * LoggerModule.forRoot({
3140
+ * provider: 'default',
3141
+ * environment: 'development'
3142
+ * })
3143
+ * ```
3144
+ */
3145
+ static forRoot(options = {}) {
3146
+ const providers = createLoggerProviders(options);
3147
+ return {
3148
+ module: _LoggerModule,
3149
+ providers,
3150
+ exports: [
3151
+ LoggerService2,
3152
+ CorrelationIdMiddleware,
3153
+ HttpLoggerInterceptor,
3154
+ LOGGER_MODULE_OPTIONS
3155
+ ]
3156
+ };
3157
+ }
3158
+ /**
3159
+ * Configures the logger module with async options.
3160
+ *
3161
+ * Supports dynamic configuration using:
3162
+ * - `useFactory`: Factory function with dependency injection
3163
+ * - `useClass`: Class implementing `LoggerOptionsFactory`
3164
+ * - `useExisting`: Existing provider implementing `LoggerOptionsFactory`
3165
+ *
3166
+ * Options from the factory/class are merged with environment preset defaults.
3167
+ *
3168
+ * @param options - Async configuration options
3169
+ * @returns Dynamic module configuration
3170
+ *
3171
+ * @example
3172
+ * ```typescript
3173
+ * // Factory with ConfigService
3174
+ * LoggerModule.forRootAsync({
3175
+ * imports: [ConfigModule],
3176
+ * useFactory: (config: ConfigService) => ({
3177
+ * environment: config.get('NODE_ENV', 'development'),
3178
+ * provider: config.get('LOG_PROVIDER', 'winston'),
3179
+ * level: config.get('LOG_LEVEL'),
3180
+ * appName: config.get('APP_NAME'),
3181
+ * }),
3182
+ * inject: [ConfigService]
3183
+ * })
3184
+ *
3185
+ * // Factory class
3186
+ * @Injectable()
3187
+ * class LoggerConfigService implements LoggerOptionsFactory {
3188
+ * createLoggerOptions(): LoggerModuleOptions {
3189
+ * return {
3190
+ * environment: 'production',
3191
+ * appName: 'my-service'
3192
+ * };
3193
+ * }
3194
+ * }
3195
+ *
3196
+ * LoggerModule.forRootAsync({
3197
+ * useClass: LoggerConfigService
3198
+ * })
3199
+ * ```
3200
+ */
3201
+ static forRootAsync(options) {
3202
+ const asyncProviders = this.createAsyncProviders(options);
3203
+ return {
3204
+ module: _LoggerModule,
3205
+ imports: options.imports || [],
3206
+ providers: [
3207
+ ...asyncProviders,
3208
+ // Default logger provider
3209
+ {
3210
+ provide: import_common41.Logger,
3211
+ useFactory: /* @__PURE__ */ __name((opts) => {
3212
+ if (opts.provider === "default") {
3213
+ const logger = new import_common41.Logger();
3214
+ if (opts.level && typeof logger.setLogLevels === "function") {
3215
+ const levels = getLevelsUpTo(opts.level);
3216
+ logger.setLogLevels(levels);
3217
+ }
3218
+ return logger;
3219
+ }
3220
+ return null;
3221
+ }, "useFactory"),
3222
+ inject: [
3223
+ LOGGER_MODULE_OPTIONS
3224
+ ]
3225
+ },
3226
+ // Unified logger service
3227
+ {
3228
+ provide: LoggerService2,
3229
+ useFactory: /* @__PURE__ */ __name((opts, defaultLogger) => {
3230
+ return new LoggerService2(opts, defaultLogger);
3231
+ }, "useFactory"),
3232
+ inject: [
3233
+ LOGGER_MODULE_OPTIONS,
3234
+ {
3235
+ token: import_common41.Logger,
3236
+ optional: true
3237
+ }
3238
+ ]
3239
+ },
3240
+ // Correlation ID middleware
3241
+ {
3242
+ provide: CorrelationIdMiddleware,
3243
+ useFactory: /* @__PURE__ */ __name(() => {
3244
+ return new CorrelationIdMiddleware({
3245
+ includeInResponse: true,
3246
+ responseHeader: "x-correlation-id"
3247
+ });
3248
+ }, "useFactory")
3249
+ },
3250
+ // HTTP logger interceptor
3251
+ {
3252
+ provide: HttpLoggerInterceptor,
3253
+ useFactory: /* @__PURE__ */ __name((logger, opts) => {
3254
+ const httpLoggerOptions = opts.httpLogger ?? {
3255
+ enableRequestLog: opts.enableHttpLogger,
3256
+ enableResponseLog: opts.enableHttpLogger
3257
+ };
3258
+ return new HttpLoggerInterceptor(logger, httpLoggerOptions);
3259
+ }, "useFactory"),
3260
+ inject: [
3261
+ LoggerService2,
3262
+ LOGGER_MODULE_OPTIONS
3263
+ ]
3264
+ }
3265
+ ],
3266
+ exports: [
3267
+ LoggerService2,
3268
+ CorrelationIdMiddleware,
3269
+ HttpLoggerInterceptor,
3270
+ LOGGER_MODULE_OPTIONS
3271
+ ]
3272
+ };
3273
+ }
3274
+ /**
3275
+ * Configures middleware for the module.
3276
+ * Middleware is registered globally in main.ts using Fastify hooks.
3277
+ */
3278
+ configure(consumer) {
3279
+ }
3280
+ /**
3281
+ * Creates async providers for dynamic module configuration.
3282
+ */
3283
+ static createAsyncProviders(options) {
3284
+ if (options.useFactory) {
3285
+ return [
3286
+ this.createAsyncOptionsProvider(options)
3287
+ ];
3288
+ }
3289
+ const providers = [
3290
+ this.createAsyncOptionsProvider(options)
3291
+ ];
3292
+ if (options.useClass) {
3293
+ providers.push({
3294
+ provide: options.useClass,
3295
+ useClass: options.useClass
3296
+ });
3297
+ }
3298
+ return providers;
3299
+ }
3300
+ /**
3301
+ * Creates the async options provider.
3302
+ */
3303
+ static createAsyncOptionsProvider(options) {
3304
+ if (options.useFactory) {
3305
+ return {
3306
+ provide: LOGGER_MODULE_OPTIONS,
3307
+ useFactory: /* @__PURE__ */ __name(async (...args) => {
3308
+ const userOptions = await options.useFactory(...args);
3309
+ return mergeWithDefaults(userOptions);
3310
+ }, "useFactory"),
3311
+ inject: options.inject || []
3312
+ };
3313
+ }
3314
+ if (options.useClass) {
3315
+ return {
3316
+ provide: LOGGER_MODULE_OPTIONS,
3317
+ useFactory: /* @__PURE__ */ __name(async (optionsFactory) => {
3318
+ const userOptions = await optionsFactory.createLoggerOptions();
3319
+ return mergeWithDefaults(userOptions);
3320
+ }, "useFactory"),
3321
+ inject: [
3322
+ options.useClass
3323
+ ]
3324
+ };
3325
+ }
3326
+ if (options.useExisting) {
3327
+ return {
3328
+ provide: LOGGER_MODULE_OPTIONS,
3329
+ useFactory: /* @__PURE__ */ __name(async (optionsFactory) => {
3330
+ const userOptions = await optionsFactory.createLoggerOptions();
3331
+ return mergeWithDefaults(userOptions);
3332
+ }, "useFactory"),
3333
+ inject: [
3334
+ options.useExisting
3335
+ ]
3336
+ };
3337
+ }
3338
+ throw new Error("LoggerModule.forRootAsync() requires one of: useFactory, useClass, or useExisting");
3339
+ }
3340
+ };
3341
+ LoggerModule = _ts_decorate17([
3342
+ (0, import_common41.Global)(),
3343
+ (0, import_common41.Module)({})
3344
+ ], LoggerModule);
2415
3345
  // Annotate the CommonJS export names for ESM import in node:
2416
3346
  0 && (module.exports = {
2417
3347
  AuthConfigModule,
@@ -2419,13 +3349,19 @@ var BadGatewayException = class extends BaseFieldException {
2419
3349
  BadRequestException,
2420
3350
  BaseFieldException,
2421
3351
  ConflictException,
3352
+ CorrelationIdMiddleware,
2422
3353
  CsrfGuard,
3354
+ DEFAULT_CORRELATION_HEADER,
2423
3355
  DatabaseModule,
2424
3356
  ForbiddenException,
2425
3357
  GoneException,
2426
3358
  HttpExceptionFilter,
3359
+ HttpLoggerInterceptor,
2427
3360
  HttpModule,
2428
3361
  InternalServerErrorException,
3362
+ LOGGER_MODULE_OPTIONS,
3363
+ LoggerModule,
3364
+ LoggerService,
2429
3365
  MethodNotAllowedException,
2430
3366
  NotAcceptableException,
2431
3367
  NotFoundException,
@@ -2447,6 +3383,12 @@ var BadGatewayException = class extends BaseFieldException {
2447
3383
  UnsupportedMediaTypeException,
2448
3384
  ValidationException,
2449
3385
  VrittiAuthGuard,
2450
- getHttpStatusTitle
3386
+ addCorrelationIdToResponse,
3387
+ correlationStorage,
3388
+ generateCorrelationId,
3389
+ getCorrelationContext,
3390
+ getHttpStatusTitle,
3391
+ runWithCorrelationContext,
3392
+ updateCorrelationContext
2451
3393
  });
2452
3394
  //# sourceMappingURL=index.cjs.map