@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.js CHANGED
@@ -143,6 +143,9 @@ import * as jwt from "jsonwebtoken";
143
143
 
144
144
  // src/database/services/primary-database.service.ts
145
145
  import { Inject as Inject2, Injectable as Injectable2, InternalServerErrorException, Logger } from "@nestjs/common";
146
+ import { Pool } from "pg";
147
+ import { drizzle } from "drizzle-orm/node-postgres";
148
+ import { eq, or } from "drizzle-orm";
146
149
 
147
150
  // src/database/constants.ts
148
151
  var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
@@ -171,8 +174,10 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
171
174
  }
172
175
  options;
173
176
  logger = new Logger(_PrimaryDatabaseService.name);
174
- /** Primary database client for querying tenant registry */
175
- primaryDbClient;
177
+ /** PostgreSQL connection pool */
178
+ pool = null;
179
+ /** Drizzle database instance */
180
+ db = null;
176
181
  /** In-memory cache: Map<tenantIdentifier, TenantConfig> */
177
182
  tenantConfigCache = /* @__PURE__ */ new Map();
178
183
  /** Cache TTL in milliseconds */
@@ -183,28 +188,24 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
183
188
  }
184
189
  async onModuleInit() {
185
190
  if (this.options.primaryDb) {
186
- await this.initializePrimaryDbClient();
191
+ await this.initializeDrizzleClient();
187
192
  }
188
193
  }
189
194
  /**
190
- * Initialize connection to primary database
195
+ * Initialize connection to primary database using Drizzle
191
196
  */
192
- async initializePrimaryDbClient() {
197
+ async initializeDrizzleClient() {
193
198
  try {
194
- const PrimaryDbClient = this.options.prismaClientConstructor;
195
199
  const databaseUrl = this.buildPrimaryDbUrl();
196
- this.primaryDbClient = new PrimaryDbClient({
197
- datasources: {
198
- db: {
199
- url: databaseUrl
200
- }
201
- },
202
- log: [
203
- "error",
204
- "warn"
205
- ]
200
+ this.pool = new Pool({
201
+ connectionString: databaseUrl,
202
+ max: this.options.maxConnections || 10
206
203
  });
207
- await this.primaryDbClient.$connect();
204
+ this.db = drizzle({
205
+ client: this.pool,
206
+ schema: this.options.drizzleSchema
207
+ });
208
+ await this.pool.query("SELECT 1");
208
209
  this.logger.log("Connected to primary database (tenant registry)");
209
210
  } catch (error) {
210
211
  this.logger.error("Failed to connect to primary database", error);
@@ -219,7 +220,7 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
219
220
  throw new Error("Primary database configuration not provided");
220
221
  }
221
222
  const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
222
- let url = `postgresql://${username}:${password}@${host}:${port}/${database}`;
223
+ let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
223
224
  const params = new URLSearchParams();
224
225
  if (schema) {
225
226
  params.set("schema", schema);
@@ -239,9 +240,9 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
239
240
  return url.replace(/:([^@]+)@/, ":****@");
240
241
  }
241
242
  /**
242
- * Get tenant configuration by identifier (ID or slug)
243
+ * Get tenant configuration by identifier (ID or subdomain)
243
244
  *
244
- * @param tenantIdentifier Tenant ID or slug
245
+ * @param tenantIdentifier Tenant ID or subdomain
245
246
  * @returns Tenant configuration or null if not found
246
247
  */
247
248
  async getTenantInfo(tenantIdentifier) {
@@ -251,45 +252,39 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
251
252
  return cached;
252
253
  }
253
254
  try {
254
- if (!this.primaryDbClient) {
255
+ if (!this.db) {
255
256
  throw new Error("Primary database client not initialized");
256
257
  }
257
258
  this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
258
- const tenant = await this.primaryDbClient.tenant.findFirst({
259
- where: {
260
- OR: [
261
- {
262
- id: tenantIdentifier
263
- },
264
- {
265
- subdomain: tenantIdentifier
266
- }
267
- ],
268
- status: "ACTIVE"
269
- },
270
- include: {
271
- databaseConfig: true
272
- }
273
- });
274
- if (!tenant) {
259
+ const schema = this.options.drizzleSchema;
260
+ const { tenants, tenantDatabaseConfigs } = schema;
261
+ 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);
262
+ if (!result.length) {
275
263
  this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
276
264
  return null;
277
265
  }
266
+ const row = result[0];
267
+ const tenant = row.tenants;
268
+ const config = row.tenant_database_configs;
269
+ if (tenant.status !== "ACTIVE") {
270
+ this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
271
+ return null;
272
+ }
278
273
  const info = {
279
274
  id: tenant.id,
280
275
  subdomain: tenant.subdomain,
281
276
  type: tenant.dbType,
282
277
  status: tenant.status,
283
278
  // For SHARED tenants: schema name
284
- schemaName: tenant.databaseConfig?.dbSchema || void 0,
279
+ schemaName: config?.dbSchema || void 0,
285
280
  // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
286
- databaseName: tenant.databaseConfig?.dbName || void 0,
287
- databaseHost: tenant.databaseConfig?.dbHost || void 0,
288
- databasePort: tenant.databaseConfig?.dbPort || void 0,
289
- databaseUsername: tenant.databaseConfig?.dbUsername ? this.decrypt(tenant.databaseConfig.dbUsername) : void 0,
290
- databasePassword: tenant.databaseConfig?.dbPassword ? this.decrypt(tenant.databaseConfig.dbPassword) : void 0,
291
- databaseSslMode: tenant.databaseConfig?.dbSslMode || void 0,
292
- connectionPoolSize: tenant.databaseConfig?.connectionPoolSize || void 0
281
+ databaseName: config?.dbName || void 0,
282
+ databaseHost: config?.dbHost || void 0,
283
+ databasePort: config?.dbPort || void 0,
284
+ databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
285
+ databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
286
+ databaseSslMode: config?.dbSslMode || void 0,
287
+ connectionPoolSize: config?.connectionPoolSize || void 0
293
288
  };
294
289
  this.cacheInfo(info);
295
290
  return info;
@@ -315,7 +310,7 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
315
310
  *
316
311
  * Useful when tenant settings are updated and cache needs to be invalidated
317
312
  *
318
- * @param tenantIdentifier Tenant ID or slug
313
+ * @param tenantIdentifier Tenant ID or subdomain
319
314
  */
320
315
  clearTenantCache(tenantIdentifier) {
321
316
  const config = this.tenantConfigCache.get(tenantIdentifier);
@@ -334,17 +329,23 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
334
329
  this.logger.log(`Cleared ${size} cached tenant configs`);
335
330
  }
336
331
  /**
337
- * Get the Prisma client for the primary database.
338
- * This is a synchronous property that returns the initialized Prisma client.
332
+ * Get the Drizzle database instance for the primary database.
333
+ * This is a synchronous property that returns the initialized Drizzle client.
339
334
  *
340
- * @returns Primary database client instance
335
+ * @returns Primary database Drizzle instance
341
336
  * @throws Error if primary database client is not initialized
342
337
  */
343
- get prismaClient() {
344
- if (!this.primaryDbClient) {
338
+ get drizzleClient() {
339
+ if (!this.db) {
345
340
  throw new Error("Primary database client not initialized");
346
341
  }
347
- return this.primaryDbClient;
342
+ return this.db;
343
+ }
344
+ /**
345
+ * Get the Drizzle schema
346
+ */
347
+ get schema() {
348
+ return this.options.drizzleSchema;
348
349
  }
349
350
  /**
350
351
  * Decrypt database credentials
@@ -358,8 +359,8 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
358
359
  return encrypted;
359
360
  }
360
361
  async onModuleDestroy() {
361
- if (this.primaryDbClient) {
362
- await this.primaryDbClient.$disconnect();
362
+ if (this.pool) {
363
+ await this.pool.end();
363
364
  this.logger.log("Disconnected from primary database");
364
365
  }
365
366
  }
@@ -904,6 +905,8 @@ TenantContextInterceptor = _ts_decorate8([
904
905
 
905
906
  // src/database/services/tenant-database.service.ts
906
907
  import { Inject as Inject3, Injectable as Injectable7, InternalServerErrorException as InternalServerErrorException2, Logger as Logger5 } from "@nestjs/common";
908
+ import { Pool as Pool2 } from "pg";
909
+ import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
907
910
  function _ts_decorate9(decorators, target, key, desc) {
908
911
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
909
912
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -928,7 +931,7 @@ var TenantDatabaseService = class _TenantDatabaseService {
928
931
  options;
929
932
  tenantContext;
930
933
  logger = new Logger5(_TenantDatabaseService.name);
931
- /** Connection pool: Map<cacheKey, DbClient> */
934
+ /** Connection pool: Map<cacheKey, TenantConnection> */
932
935
  clients = /* @__PURE__ */ new Map();
933
936
  /** Track last usage time for idle connection cleanup */
934
937
  clientLastUsed = /* @__PURE__ */ new Map();
@@ -940,17 +943,23 @@ var TenantDatabaseService = class _TenantDatabaseService {
940
943
  this.startConnectionCleaner();
941
944
  }
942
945
  /**
943
- * Get the Prisma client for the current tenant's database.
946
+ * Get the Drizzle client for the current tenant's database.
944
947
  * This returns the tenant-scoped database client.
945
948
  *
946
- * @returns Tenant-scoped database client instance
949
+ * @returns Tenant-scoped Drizzle database instance
947
950
  * @throws UnauthorizedException if tenant context not set
948
951
  * @throws InternalServerErrorException if connection fails
949
952
  */
950
- get prismaClient() {
953
+ get drizzleClient() {
951
954
  return this.getDbClient();
952
955
  }
953
956
  /**
957
+ * Get the Drizzle schema
958
+ */
959
+ get schema() {
960
+ return this.options.drizzleSchema;
961
+ }
962
+ /**
954
963
  * Get tenant-scoped database client for the current request/message
955
964
  *
956
965
  * This method:
@@ -958,66 +967,61 @@ var TenantDatabaseService = class _TenantDatabaseService {
958
967
  * 2. Builds a connection URL based on tenant type
959
968
  * 3. Returns cached client if exists, otherwise creates new one
960
969
  *
961
- * @returns Promise<Database client instance>
970
+ * @returns Drizzle database instance
962
971
  * @throws UnauthorizedException if tenant context not set
963
972
  * @throws InternalServerErrorException if connection fails
964
- *
965
- * @example
966
- * const dbClient = await tenantDatabase.getDbClient<PrismaClient>();
967
- * const users = await dbClient.user.findMany();
968
973
  */
969
- async getDbClient() {
974
+ getDbClient() {
970
975
  const tenant = this.tenantContext.getTenant();
971
976
  const cacheKey = this.buildCacheKey(tenant);
972
- if (this.clients.has(cacheKey)) {
977
+ const existing = this.clients.get(cacheKey);
978
+ if (existing) {
973
979
  this.clientLastUsed.set(cacheKey, Date.now());
974
980
  this.logger.debug(`Reusing cached connection: ${cacheKey}`);
975
- return this.clients.get(cacheKey);
981
+ return existing.db;
976
982
  }
977
983
  this.logger.log(`Creating new database connection: ${cacheKey}`);
978
- const client = await this.createDbClient(tenant);
979
- this.clients.set(cacheKey, client);
984
+ const connection = this.createDbClientSync(tenant);
985
+ this.clients.set(cacheKey, connection);
980
986
  this.clientLastUsed.set(cacheKey, Date.now());
981
- return client;
987
+ return connection.db;
982
988
  }
983
989
  /**
984
- * Create a new database client for the given tenant
990
+ * Create a new database client for the given tenant (synchronous)
985
991
  */
986
- async createDbClient(tenant) {
992
+ createDbClientSync(tenant) {
987
993
  try {
988
994
  const databaseUrl = this.buildTenantDbUrl(tenant);
989
- const PrismaClient = await this.options.prismaClientConstructor;
990
- const client = new PrismaClient({
991
- datasources: {
992
- db: {
993
- url: databaseUrl
994
- }
995
- },
996
- log: [
997
- "error",
998
- "warn"
999
- ]
995
+ const pool = new Pool2({
996
+ connectionString: databaseUrl,
997
+ max: tenant.connectionPoolSize || this.options.maxConnections || 10
998
+ });
999
+ const db = drizzle2({
1000
+ client: pool,
1001
+ schema: this.options.drizzleSchema
1000
1002
  });
1001
- await client.$connect();
1002
1003
  this.logger.log(`Connected to database for tenant: ${tenant.subdomain}`);
1003
- return client;
1004
+ return {
1005
+ pool,
1006
+ db
1007
+ };
1004
1008
  } catch (error) {
1005
1009
  this.logger.error(`Failed to create database connection for tenant: ${tenant.subdomain}`, error);
1006
1010
  throw new InternalServerErrorException2("Failed to connect to tenant database");
1007
1011
  }
1008
1012
  }
1009
1013
  /**
1010
- * Build connection URL for enterprise tenant (dedicated database)
1014
+ * Build connection URL for tenant (dedicated database)
1011
1015
  */
1012
1016
  buildTenantDbUrl(tenant) {
1013
1017
  const { databaseHost, databasePort, databaseName, databaseUsername, databasePassword, databaseSslMode } = tenant;
1014
1018
  if (!databaseHost || !databaseName || !databaseUsername) {
1015
- throw new Error(`Enterprise tenant ${tenant.subdomain} missing database configuration`);
1019
+ throw new Error(`Tenant ${tenant.subdomain} missing database configuration`);
1016
1020
  }
1017
1021
  const port = databasePort || 5432;
1018
1022
  const sslMode = databaseSslMode || "require";
1019
- const connectionUrl = `postgresql://${databaseUsername}:${databasePassword}@${databaseHost}:${port}/${databaseName}?sslmode=${sslMode}`;
1020
- this.logger.debug(`Enterprise connection URL: ${this.maskPassword(connectionUrl)}`);
1023
+ const connectionUrl = `postgresql://${databaseUsername}:${encodeURIComponent(databasePassword || "")}@${databaseHost}:${port}/${databaseName}?sslmode=${sslMode}`;
1024
+ this.logger.debug(`Tenant connection URL: ${this.maskPassword(connectionUrl)}`);
1021
1025
  return connectionUrl;
1022
1026
  }
1023
1027
  /**
@@ -1039,19 +1043,20 @@ var TenantDatabaseService = class _TenantDatabaseService {
1039
1043
  /**
1040
1044
  * Clean up idle connections that haven't been used recently
1041
1045
  */
1042
- cleanupIdleConnections() {
1046
+ async cleanupIdleConnections() {
1043
1047
  const now = Date.now();
1044
1048
  const maxIdle = this.options.connectionCacheTTL || 3e5;
1045
1049
  let cleaned = 0;
1046
1050
  for (const [key, lastUsed] of this.clientLastUsed.entries()) {
1047
1051
  if (now - lastUsed > maxIdle) {
1048
- const client = this.clients.get(key);
1049
- if (client) {
1050
- client.$disconnect().then(() => {
1052
+ const connection = this.clients.get(key);
1053
+ if (connection) {
1054
+ try {
1055
+ await connection.pool.end();
1051
1056
  this.logger.debug(`Cleaned up idle connection: ${key}`);
1052
- }).catch((error) => {
1057
+ } catch (error) {
1053
1058
  this.logger.error(`Error disconnecting idle client: ${key}`, error);
1054
- });
1059
+ }
1055
1060
  this.clients.delete(key);
1056
1061
  this.clientLastUsed.delete(key);
1057
1062
  cleaned++;
@@ -1082,9 +1087,9 @@ var TenantDatabaseService = class _TenantDatabaseService {
1082
1087
  clearInterval(this.cleanupInterval);
1083
1088
  }
1084
1089
  this.logger.log(`Disconnecting ${this.clients.size} database connections`);
1085
- const disconnectPromises = Array.from(this.clients.entries()).map(async ([key, client]) => {
1090
+ const disconnectPromises = Array.from(this.clients.entries()).map(async ([key, connection]) => {
1086
1091
  try {
1087
- await client.$disconnect();
1092
+ await connection.pool.end();
1088
1093
  this.logger.debug(`Disconnected: ${key}`);
1089
1094
  } catch (error) {
1090
1095
  this.logger.error(`Error disconnecting client: ${key}`, error);
@@ -1220,56 +1225,64 @@ DatabaseModule = _ts_decorate10([
1220
1225
 
1221
1226
  // src/database/repositories/primary-base.repository.ts
1222
1227
  import { Logger as Logger6 } from "@nestjs/common";
1228
+ import { eq as eq2, sql, getTableName } from "drizzle-orm";
1223
1229
  var PrimaryBaseRepository = class {
1224
1230
  static {
1225
1231
  __name(this, "PrimaryBaseRepository");
1226
1232
  }
1227
1233
  database;
1234
+ table;
1228
1235
  logger;
1229
- modelGetter;
1230
1236
  /**
1231
- * Lazy getter for Prisma client.
1237
+ * The table name extracted from the Drizzle table at runtime.
1238
+ * Used to access the query API for this repository's table.
1239
+ */
1240
+ tableName;
1241
+ /**
1242
+ * Lazy getter for Drizzle client.
1232
1243
  * Accesses the client from the database service only when needed,
1233
1244
  * avoiding initialization timing issues with NestJS lifecycle.
1234
1245
  */
1235
- get prisma() {
1236
- return this.database.prismaClient;
1246
+ get db() {
1247
+ return this.database.drizzleClient;
1237
1248
  }
1238
1249
  /**
1239
- * Lazy getter for the Prisma model delegate.
1240
- * Returns the specific model (e.g., prisma.user, prisma.tenant) for this repository.
1250
+ * Model query API for THIS repository's table (Prisma-like syntax)
1251
+ * Scoped to only the table this repository manages.
1252
+ * Returns a type-safe wrapper around Drizzle's RelationalQueryBuilder.
1253
+ *
1254
+ * @example
1255
+ * ```typescript
1256
+ * // Use relational queries with type safety
1257
+ * const user = await this.model.findFirst({
1258
+ * where: eq(users.id, id),
1259
+ * with: { posts: true, profile: true }
1260
+ * });
1261
+ * ```
1241
1262
  */
1242
1263
  get model() {
1243
- return this.modelGetter(this.prisma);
1264
+ return this.database.drizzleClient.query[this.tableName];
1244
1265
  }
1245
1266
  /**
1246
1267
  * Create a new repository instance
1247
1268
  *
1248
1269
  * @param database - The primary database service
1249
- * @param getModel - Function that returns the Prisma model delegate from the client
1270
+ * @param table - The Drizzle table schema object
1250
1271
  *
1251
1272
  * @example
1252
1273
  * ```typescript
1253
- * // Standard usage with full parameter name
1254
- * constructor(database: PrimaryDatabaseService) {
1255
- * super(database, (prisma) => prisma.user);
1256
- * }
1257
- *
1258
- * // Short syntax
1259
- * constructor(database: PrimaryDatabaseService) {
1260
- * super(database, (p) => p.user);
1261
- * }
1274
+ * import { users } from '@/db/schema';
1262
1275
  *
1263
- * // Complex model names
1264
1276
  * constructor(database: PrimaryDatabaseService) {
1265
- * super(database, (p) => p.emailVerification);
1277
+ * super(database, users);
1266
1278
  * }
1267
1279
  * ```
1268
1280
  */
1269
- constructor(database, getModel) {
1281
+ constructor(database, table) {
1270
1282
  this.database = database;
1283
+ this.table = table;
1284
+ this.tableName = getTableName(table);
1271
1285
  this.logger = new Logger6(this.constructor.name);
1272
- this.modelGetter = getModel;
1273
1286
  this.logger.debug(`Initialized ${this.constructor.name}`);
1274
1287
  }
1275
1288
  /**
@@ -1282,21 +1295,20 @@ var PrimaryBaseRepository = class {
1282
1295
  * ```typescript
1283
1296
  * const user = await userRepository.create({
1284
1297
  * email: 'user@example.com',
1285
- * name: 'John Doe'
1298
+ * firstName: 'John'
1286
1299
  * });
1287
1300
  * ```
1288
1301
  */
1289
1302
  async create(data) {
1290
1303
  this.logger.log("Creating record");
1291
- return await this.model.create({
1292
- data
1293
- });
1304
+ const results = await this.db.insert(this.table).values(data).returning();
1305
+ return results[0];
1294
1306
  }
1295
1307
  /**
1296
1308
  * Find a single record by ID
1297
1309
  *
1298
1310
  * @param id - The record ID
1299
- * @returns Promise resolving to the record or null if not found
1311
+ * @returns Promise resolving to the record or undefined if not found
1300
1312
  *
1301
1313
  * @example
1302
1314
  * ```typescript
@@ -1305,59 +1317,54 @@ var PrimaryBaseRepository = class {
1305
1317
  */
1306
1318
  async findById(id) {
1307
1319
  this.logger.debug(`Finding record by ID: ${id}`);
1308
- return await this.model.findUnique({
1309
- where: {
1310
- id
1311
- }
1320
+ const idColumn = this.table.id;
1321
+ return this.model.findFirst({
1322
+ where: eq2(idColumn, id)
1312
1323
  });
1313
1324
  }
1314
1325
  /**
1315
1326
  * Find a single record with custom where clause
1316
1327
  *
1317
- * @param where - The where clause or findUnique args
1318
- * @returns Promise resolving to the record or null if not found
1328
+ * @param where - SQL condition
1329
+ * @returns Promise resolving to the record or undefined if not found
1319
1330
  *
1320
1331
  * @example
1321
1332
  * ```typescript
1322
- * // Simple where clause
1323
- * const user = await userRepository.findOne({ email: 'user@example.com' });
1324
- *
1325
- * // With include
1326
- * const user = await userRepository.findOne({
1327
- * where: { email: 'user@example.com' },
1328
- * include: { posts: true }
1329
- * });
1333
+ * import { eq } from 'drizzle-orm';
1334
+ * const user = await userRepository.findOne(eq(users.email, 'user@example.com'));
1330
1335
  * ```
1331
1336
  */
1332
1337
  async findOne(where) {
1333
1338
  this.logger.debug("Finding record with custom query");
1334
- return await this.model.findUnique(typeof where === "object" && "where" in where ? where : {
1339
+ return this.model.findFirst({
1335
1340
  where
1336
1341
  });
1337
1342
  }
1338
1343
  /**
1339
1344
  * Find multiple records
1340
1345
  *
1341
- * @param args - Prisma findMany arguments (where, orderBy, take, skip, etc.)
1346
+ * @param options - Query options (where, orderBy, limit, offset)
1342
1347
  * @returns Promise resolving to an array of records
1343
1348
  *
1344
1349
  * @example
1345
1350
  * ```typescript
1351
+ * import { eq, desc } from 'drizzle-orm';
1352
+ *
1346
1353
  * // Find all users
1347
1354
  * const users = await userRepository.findMany();
1348
1355
  *
1349
1356
  * // Find with filtering and pagination
1350
1357
  * const users = await userRepository.findMany({
1351
- * where: { status: 'ACTIVE' },
1352
- * orderBy: { createdAt: 'desc' },
1353
- * take: 10,
1354
- * skip: 0
1358
+ * where: eq(users.accountStatus, 'ACTIVE'),
1359
+ * orderBy: desc(users.createdAt),
1360
+ * limit: 10,
1361
+ * offset: 0
1355
1362
  * });
1356
1363
  * ```
1357
1364
  */
1358
- async findMany(args) {
1365
+ async findMany(options) {
1359
1366
  this.logger.debug("Finding multiple records");
1360
- return await this.model.findMany(args);
1367
+ return this.model.findMany(options);
1361
1368
  }
1362
1369
  /**
1363
1370
  * Update a record by ID
@@ -1369,41 +1376,40 @@ var PrimaryBaseRepository = class {
1369
1376
  * @example
1370
1377
  * ```typescript
1371
1378
  * const user = await userRepository.update('user-id-123', {
1372
- * name: 'Jane Doe'
1379
+ * firstName: 'Jane'
1373
1380
  * });
1374
1381
  * ```
1375
1382
  */
1376
1383
  async update(id, data) {
1377
1384
  this.logger.log(`Updating record with ID: ${id}`);
1378
- return await this.model.update({
1379
- where: {
1380
- id
1381
- },
1382
- data
1383
- });
1385
+ const idColumn = this.table.id;
1386
+ const results = await this.db.update(this.table).set(data).where(eq2(idColumn, id)).returning();
1387
+ return results[0];
1384
1388
  }
1385
1389
  /**
1386
1390
  * Update multiple records
1387
1391
  *
1388
- * @param where - The where clause to match records
1392
+ * @param where - SQL condition to match records
1389
1393
  * @param data - The data to update
1390
1394
  * @returns Promise resolving to the count of updated records
1391
1395
  *
1392
1396
  * @example
1393
1397
  * ```typescript
1398
+ * import { eq } from 'drizzle-orm';
1399
+ *
1394
1400
  * const result = await userRepository.updateMany(
1395
- * { status: 'PENDING' },
1396
- * { status: 'ACTIVE' }
1401
+ * eq(users.accountStatus, 'PENDING'),
1402
+ * { accountStatus: 'ACTIVE' }
1397
1403
  * );
1398
1404
  * console.log(`Updated ${result.count} users`);
1399
1405
  * ```
1400
1406
  */
1401
1407
  async updateMany(where, data) {
1402
1408
  this.logger.log("Updating multiple records");
1403
- return await this.model.updateMany({
1404
- where,
1405
- data
1406
- });
1409
+ const result = await this.db.update(this.table).set(data).where(where);
1410
+ return {
1411
+ count: result.rowCount ?? 0
1412
+ };
1407
1413
  }
1408
1414
  /**
1409
1415
  * Delete a record by ID
@@ -1418,127 +1424,143 @@ var PrimaryBaseRepository = class {
1418
1424
  */
1419
1425
  async delete(id) {
1420
1426
  this.logger.log(`Deleting record with ID: ${id}`);
1421
- return await this.model.delete({
1422
- where: {
1423
- id
1424
- }
1425
- });
1427
+ const idColumn = this.table.id;
1428
+ const results = await this.db.delete(this.table).where(eq2(idColumn, id)).returning();
1429
+ return results[0];
1426
1430
  }
1427
1431
  /**
1428
1432
  * Delete multiple records
1429
1433
  *
1430
- * @param where - The where clause to match records
1434
+ * @param where - SQL condition to match records
1431
1435
  * @returns Promise resolving to the count of deleted records
1432
1436
  *
1433
1437
  * @example
1434
1438
  * ```typescript
1435
- * const result = await userRepository.deleteMany({
1436
- * status: 'INACTIVE',
1437
- * createdAt: { lt: new Date('2020-01-01') }
1438
- * });
1439
+ * import { lt } from 'drizzle-orm';
1440
+ *
1441
+ * const result = await userRepository.deleteMany(
1442
+ * lt(users.createdAt, new Date('2020-01-01'))
1443
+ * );
1439
1444
  * console.log(`Deleted ${result.count} users`);
1440
1445
  * ```
1441
1446
  */
1442
1447
  async deleteMany(where) {
1443
1448
  this.logger.log("Deleting multiple records");
1444
- return await this.model.deleteMany({
1445
- where
1446
- });
1449
+ const result = await this.db.delete(this.table).where(where);
1450
+ return {
1451
+ count: result.rowCount ?? 0
1452
+ };
1447
1453
  }
1448
1454
  /**
1449
1455
  * Count records
1450
1456
  *
1451
- * @param where - Optional where clause to filter records
1457
+ * @param where - Optional SQL condition to filter records
1452
1458
  * @returns Promise resolving to the count of records
1453
1459
  *
1454
1460
  * @example
1455
1461
  * ```typescript
1462
+ * import { eq } from 'drizzle-orm';
1463
+ *
1456
1464
  * // Count all users
1457
1465
  * const total = await userRepository.count();
1458
1466
  *
1459
1467
  * // Count active users
1460
- * const activeCount = await userRepository.count({ status: 'ACTIVE' });
1468
+ * const activeCount = await userRepository.count(
1469
+ * eq(users.accountStatus, 'ACTIVE')
1470
+ * );
1461
1471
  * ```
1462
1472
  */
1463
1473
  async count(where) {
1464
1474
  this.logger.debug("Counting records");
1465
- return await this.model.count({
1466
- where
1467
- });
1475
+ let query = this.db.select({
1476
+ count: sql`count(*)::int`
1477
+ }).from(this.table).$dynamic();
1478
+ if (where) {
1479
+ query = query.where(where);
1480
+ }
1481
+ const results = await query;
1482
+ return results[0].count;
1468
1483
  }
1469
1484
  /**
1470
1485
  * Check if a record exists
1471
1486
  *
1472
- * @param where - The where clause to match records
1487
+ * @param where - SQL condition to match records
1473
1488
  * @returns Promise resolving to true if at least one record exists, false otherwise
1474
1489
  *
1475
1490
  * @example
1476
1491
  * ```typescript
1477
- * const emailExists = await userRepository.exists({
1478
- * email: 'user@example.com'
1479
- * });
1492
+ * import { eq } from 'drizzle-orm';
1493
+ *
1494
+ * const emailExists = await userRepository.exists(
1495
+ * eq(users.email, 'user@example.com')
1496
+ * );
1480
1497
  * ```
1481
1498
  */
1482
1499
  async exists(where) {
1483
- const count = await this.model.count({
1484
- where
1485
- });
1500
+ const count = await this.count(where);
1486
1501
  return count > 0;
1487
1502
  }
1488
1503
  };
1489
1504
 
1490
1505
  // src/database/repositories/tenant-base.repository.ts
1491
1506
  import { Logger as Logger7 } from "@nestjs/common";
1507
+ import { eq as eq3, sql as sql2, getTableName as getTableName2 } from "drizzle-orm";
1492
1508
  var TenantBaseRepository = class {
1493
1509
  static {
1494
1510
  __name(this, "TenantBaseRepository");
1495
1511
  }
1496
1512
  database;
1513
+ table;
1497
1514
  logger;
1498
- modelGetter;
1499
1515
  /**
1500
- * Lazy getter for Prisma client.
1516
+ * The table name extracted from the Drizzle table at runtime.
1517
+ * Used to access the query API for this repository's table.
1518
+ */
1519
+ tableName;
1520
+ /**
1521
+ * Lazy getter for Drizzle client.
1501
1522
  * Accesses the client from the database service only when needed,
1502
1523
  * avoiding initialization timing issues with NestJS lifecycle.
1503
1524
  */
1504
- get prisma() {
1505
- return this.database.prismaClient;
1525
+ get db() {
1526
+ return this.database.drizzleClient;
1506
1527
  }
1507
1528
  /**
1508
- * Lazy getter for the Prisma model delegate.
1509
- * Returns the specific model (e.g., prisma.product, prisma.order) for this repository.
1529
+ * Model query API for THIS repository's table (Prisma-like syntax)
1530
+ * Scoped to only the table this repository manages
1531
+ *
1532
+ * @example
1533
+ * ```typescript
1534
+ * // Use relational queries with type safety
1535
+ * const product = await this.model.findFirst({
1536
+ * where: eq(products.id, id),
1537
+ * with: { category: true, variants: true }
1538
+ * });
1539
+ * ```
1510
1540
  */
1511
1541
  get model() {
1512
- return this.modelGetter(this.prisma);
1542
+ return this.database.drizzleClient.query[this.tableName];
1513
1543
  }
1514
1544
  /**
1515
1545
  * Create a new repository instance
1516
1546
  *
1517
1547
  * @param database - The tenant database service
1518
- * @param getModel - Function that returns the Prisma model delegate from the client
1548
+ * @param table - The Drizzle table schema object
1519
1549
  *
1520
1550
  * @example
1521
1551
  * ```typescript
1522
- * // Standard usage with full parameter name
1523
- * constructor(database: TenantDatabaseService) {
1524
- * super(database, (prisma) => prisma.product);
1525
- * }
1526
- *
1527
- * // Short syntax
1528
- * constructor(database: TenantDatabaseService) {
1529
- * super(database, (p) => p.product);
1530
- * }
1552
+ * import { products } from '@/db/schema';
1531
1553
  *
1532
- * // Complex model names
1533
1554
  * constructor(database: TenantDatabaseService) {
1534
- * super(database, (p) => p.inventoryItem);
1555
+ * super(database, products);
1535
1556
  * }
1536
1557
  * ```
1537
1558
  */
1538
- constructor(database, getModel) {
1559
+ constructor(database, table) {
1539
1560
  this.database = database;
1561
+ this.table = table;
1562
+ this.tableName = getTableName2(table);
1540
1563
  this.logger = new Logger7(this.constructor.name);
1541
- this.modelGetter = getModel;
1542
1564
  this.logger.debug(`Initialized ${this.constructor.name}`);
1543
1565
  }
1544
1566
  /**
@@ -1558,9 +1580,8 @@ var TenantBaseRepository = class {
1558
1580
  */
1559
1581
  async create(data) {
1560
1582
  this.logger.log("Creating record");
1561
- return await this.model.create({
1562
- data
1563
- });
1583
+ const results = await this.db.insert(this.table).values(data).returning();
1584
+ return results[0];
1564
1585
  }
1565
1586
  /**
1566
1587
  * Find a single record by ID
@@ -1575,59 +1596,65 @@ var TenantBaseRepository = class {
1575
1596
  */
1576
1597
  async findById(id) {
1577
1598
  this.logger.debug(`Finding record by ID: ${id}`);
1578
- return await this.model.findUnique({
1579
- where: {
1580
- id
1581
- }
1582
- });
1599
+ const idColumn = this.table.id;
1600
+ const results = await this.db.select().from(this.table).where(eq3(idColumn, id)).limit(1);
1601
+ return results[0] ?? null;
1583
1602
  }
1584
1603
  /**
1585
1604
  * Find a single record with custom where clause
1586
1605
  *
1587
- * @param where - The where clause or findUnique args
1606
+ * @param where - SQL condition
1588
1607
  * @returns Promise resolving to the record or null if not found
1589
1608
  *
1590
1609
  * @example
1591
1610
  * ```typescript
1592
- * // Simple where clause
1593
- * const product = await productRepository.findOne({ sku: 'WDG-001' });
1594
- *
1595
- * // With include
1596
- * const product = await productRepository.findOne({
1597
- * where: { sku: 'WDG-001' },
1598
- * include: { category: true }
1599
- * });
1611
+ * import { eq } from 'drizzle-orm';
1612
+ * const product = await productRepository.findOne(eq(products.sku, 'WDG-001'));
1600
1613
  * ```
1601
1614
  */
1602
1615
  async findOne(where) {
1603
1616
  this.logger.debug("Finding record with custom query");
1604
- return await this.model.findUnique(typeof where === "object" && "where" in where ? where : {
1605
- where
1606
- });
1617
+ const results = await this.db.select().from(this.table).where(where).limit(1);
1618
+ return results[0] ?? null;
1607
1619
  }
1608
1620
  /**
1609
1621
  * Find multiple records
1610
1622
  *
1611
- * @param args - Prisma findMany arguments (where, orderBy, take, skip, etc.)
1623
+ * @param options - Query options (where, orderBy, limit, offset)
1612
1624
  * @returns Promise resolving to an array of records
1613
1625
  *
1614
1626
  * @example
1615
1627
  * ```typescript
1628
+ * import { eq, desc } from 'drizzle-orm';
1629
+ *
1616
1630
  * // Find all products
1617
1631
  * const products = await productRepository.findMany();
1618
1632
  *
1619
1633
  * // Find with filtering and pagination
1620
1634
  * const products = await productRepository.findMany({
1621
- * where: { status: 'ACTIVE' },
1622
- * orderBy: { createdAt: 'desc' },
1623
- * take: 10,
1624
- * skip: 0
1635
+ * where: eq(products.status, 'ACTIVE'),
1636
+ * orderBy: desc(products.createdAt),
1637
+ * limit: 10,
1638
+ * offset: 0
1625
1639
  * });
1626
1640
  * ```
1627
1641
  */
1628
- async findMany(args) {
1642
+ async findMany(options) {
1629
1643
  this.logger.debug("Finding multiple records");
1630
- return await this.model.findMany(args);
1644
+ let query = this.db.select().from(this.table).$dynamic();
1645
+ if (options?.where) {
1646
+ query = query.where(options.where);
1647
+ }
1648
+ if (options?.orderBy) {
1649
+ query = query.orderBy(options.orderBy);
1650
+ }
1651
+ if (options?.limit) {
1652
+ query = query.limit(options.limit);
1653
+ }
1654
+ if (options?.offset) {
1655
+ query = query.offset(options.offset);
1656
+ }
1657
+ return await query;
1631
1658
  }
1632
1659
  /**
1633
1660
  * Update a record by ID
@@ -1645,24 +1672,23 @@ var TenantBaseRepository = class {
1645
1672
  */
1646
1673
  async update(id, data) {
1647
1674
  this.logger.log(`Updating record with ID: ${id}`);
1648
- return await this.model.update({
1649
- where: {
1650
- id
1651
- },
1652
- data
1653
- });
1675
+ const idColumn = this.table.id;
1676
+ const results = await this.db.update(this.table).set(data).where(eq3(idColumn, id)).returning();
1677
+ return results[0];
1654
1678
  }
1655
1679
  /**
1656
1680
  * Update multiple records
1657
1681
  *
1658
- * @param where - The where clause to match records
1682
+ * @param where - SQL condition to match records
1659
1683
  * @param data - The data to update
1660
1684
  * @returns Promise resolving to the count of updated records
1661
1685
  *
1662
1686
  * @example
1663
1687
  * ```typescript
1688
+ * import { eq } from 'drizzle-orm';
1689
+ *
1664
1690
  * const result = await productRepository.updateMany(
1665
- * { status: 'PENDING' },
1691
+ * eq(products.status, 'PENDING'),
1666
1692
  * { status: 'ACTIVE' }
1667
1693
  * );
1668
1694
  * console.log(`Updated ${result.count} products`);
@@ -1670,10 +1696,10 @@ var TenantBaseRepository = class {
1670
1696
  */
1671
1697
  async updateMany(where, data) {
1672
1698
  this.logger.log("Updating multiple records");
1673
- return await this.model.updateMany({
1674
- where,
1675
- data
1676
- });
1699
+ const result = await this.db.update(this.table).set(data).where(where);
1700
+ return {
1701
+ count: result.rowCount ?? 0
1702
+ };
1677
1703
  }
1678
1704
  /**
1679
1705
  * Delete a record by ID
@@ -1688,71 +1714,80 @@ var TenantBaseRepository = class {
1688
1714
  */
1689
1715
  async delete(id) {
1690
1716
  this.logger.log(`Deleting record with ID: ${id}`);
1691
- return await this.model.delete({
1692
- where: {
1693
- id
1694
- }
1695
- });
1717
+ const idColumn = this.table.id;
1718
+ const results = await this.db.delete(this.table).where(eq3(idColumn, id)).returning();
1719
+ return results[0];
1696
1720
  }
1697
1721
  /**
1698
1722
  * Delete multiple records
1699
1723
  *
1700
- * @param where - The where clause to match records
1724
+ * @param where - SQL condition to match records
1701
1725
  * @returns Promise resolving to the count of deleted records
1702
1726
  *
1703
1727
  * @example
1704
1728
  * ```typescript
1705
- * const result = await productRepository.deleteMany({
1706
- * status: 'INACTIVE',
1707
- * createdAt: { lt: new Date('2020-01-01') }
1708
- * });
1729
+ * import { lt } from 'drizzle-orm';
1730
+ *
1731
+ * const result = await productRepository.deleteMany(
1732
+ * lt(products.createdAt, new Date('2020-01-01'))
1733
+ * );
1709
1734
  * console.log(`Deleted ${result.count} products`);
1710
1735
  * ```
1711
1736
  */
1712
1737
  async deleteMany(where) {
1713
1738
  this.logger.log("Deleting multiple records");
1714
- return await this.model.deleteMany({
1715
- where
1716
- });
1739
+ const result = await this.db.delete(this.table).where(where);
1740
+ return {
1741
+ count: result.rowCount ?? 0
1742
+ };
1717
1743
  }
1718
1744
  /**
1719
1745
  * Count records
1720
1746
  *
1721
- * @param where - Optional where clause to filter records
1747
+ * @param where - Optional SQL condition to filter records
1722
1748
  * @returns Promise resolving to the count of records
1723
1749
  *
1724
1750
  * @example
1725
1751
  * ```typescript
1752
+ * import { eq } from 'drizzle-orm';
1753
+ *
1726
1754
  * // Count all products
1727
1755
  * const total = await productRepository.count();
1728
1756
  *
1729
1757
  * // Count active products
1730
- * const activeCount = await productRepository.count({ status: 'ACTIVE' });
1758
+ * const activeCount = await productRepository.count(
1759
+ * eq(products.status, 'ACTIVE')
1760
+ * );
1731
1761
  * ```
1732
1762
  */
1733
1763
  async count(where) {
1734
1764
  this.logger.debug("Counting records");
1735
- return await this.model.count({
1736
- where
1737
- });
1765
+ let query = this.db.select({
1766
+ count: sql2`count(*)::int`
1767
+ }).from(this.table).$dynamic();
1768
+ if (where) {
1769
+ query = query.where(where);
1770
+ }
1771
+ const results = await query;
1772
+ return results[0].count;
1738
1773
  }
1739
1774
  /**
1740
1775
  * Check if a record exists
1741
1776
  *
1742
- * @param where - The where clause to match records
1777
+ * @param where - SQL condition to match records
1743
1778
  * @returns Promise resolving to true if at least one record exists, false otherwise
1744
1779
  *
1745
1780
  * @example
1746
1781
  * ```typescript
1747
- * const skuExists = await productRepository.exists({
1748
- * sku: 'WDG-001'
1749
- * });
1782
+ * import { eq } from 'drizzle-orm';
1783
+ *
1784
+ * const skuExists = await productRepository.exists(
1785
+ * eq(products.sku, 'WDG-001')
1786
+ * );
1750
1787
  * ```
1751
1788
  */
1752
1789
  async exists(where) {
1753
- const count = await this.model.count({
1754
- where
1755
- });
1790
+ const count = await this.count(where);
1756
1791
  return count > 0;
1757
1792
  }
1758
1793
  };
@@ -1909,15 +1944,16 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
1909
1944
  const exceptionResponse = exception.getResponse();
1910
1945
  if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
1911
1946
  const responseObj = exceptionResponse;
1912
- if (responseObj.errors && Array.isArray(responseObj.errors)) {
1947
+ if ("errors" in responseObj && Array.isArray(responseObj.errors)) {
1913
1948
  errors = responseObj.errors;
1914
- detail = responseObj.detail || exception.message;
1915
- } else if (responseObj.message && Array.isArray(responseObj.message)) {
1949
+ detail = ("detail" in responseObj ? responseObj.detail : void 0) || exception.message;
1950
+ } else if ("message" in responseObj && Array.isArray(responseObj.message)) {
1916
1951
  errors = responseObj.message.map((msg) => {
1917
- if (typeof msg === "object" && msg.property && msg.constraints) {
1952
+ if (typeof msg === "object" && "property" in msg && "constraints" in msg) {
1953
+ const constraintValues = Object.values(msg.constraints);
1918
1954
  return {
1919
1955
  field: msg.property,
1920
- message: Object.values(msg.constraints)[0]
1956
+ message: constraintValues[0] ?? "Validation failed"
1921
1957
  };
1922
1958
  }
1923
1959
  return {
@@ -1925,13 +1961,14 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
1925
1961
  };
1926
1962
  });
1927
1963
  detail = "Validation failed";
1928
- } else if (responseObj.message) {
1964
+ } else if ("message" in responseObj) {
1965
+ const message = responseObj.message;
1929
1966
  errors = [
1930
1967
  {
1931
- message: Array.isArray(responseObj.message) ? responseObj.message.join(", ") : responseObj.message
1968
+ message: Array.isArray(message) ? message.join(", ") : message
1932
1969
  }
1933
1970
  ];
1934
- detail = responseObj.error || exception.message;
1971
+ detail = ("error" in responseObj ? responseObj.error : void 0) || exception.message;
1935
1972
  }
1936
1973
  } else if (typeof exceptionResponse === "string") {
1937
1974
  errors = [
@@ -1942,7 +1979,9 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
1942
1979
  detail = exceptionResponse;
1943
1980
  }
1944
1981
  } else {
1945
- this.logger.error("Unexpected error:", exception);
1982
+ const errorMessage = exception instanceof Error ? exception.message : "Unknown error";
1983
+ const stack = exception instanceof Error ? exception.stack : void 0;
1984
+ this.logger.error(`Unexpected error: ${errorMessage}`, stack);
1946
1985
  errors = [
1947
1986
  {
1948
1987
  message: "An unexpected error occurred"
@@ -2345,19 +2384,904 @@ var BadGatewayException = class extends BaseFieldException {
2345
2384
  }
2346
2385
  }
2347
2386
  };
2387
+
2388
+ // src/logger/logger.module.ts
2389
+ import { Global as Global4, Module as Module5, Logger as Logger11 } from "@nestjs/common";
2390
+
2391
+ // src/logger/services/logger.service.ts
2392
+ import { Injectable as Injectable9, Logger as Logger10, Optional } from "@nestjs/common";
2393
+ import { createLogger, format, transports } from "winston";
2394
+ import DailyRotateFile from "winston-daily-rotate-file";
2395
+
2396
+ // src/logger/utils/index.ts
2397
+ import { AsyncLocalStorage } from "async_hooks";
2398
+ import { randomUUID } from "crypto";
2399
+ var correlationStorage = new AsyncLocalStorage();
2400
+ function getCorrelationContext() {
2401
+ return correlationStorage.getStore();
2402
+ }
2403
+ __name(getCorrelationContext, "getCorrelationContext");
2404
+ function runWithCorrelationContext(context, callback) {
2405
+ return correlationStorage.run(context, callback);
2406
+ }
2407
+ __name(runWithCorrelationContext, "runWithCorrelationContext");
2408
+ function updateCorrelationContext(updates) {
2409
+ const context = correlationStorage.getStore();
2410
+ if (context) {
2411
+ Object.assign(context, updates);
2412
+ }
2413
+ }
2414
+ __name(updateCorrelationContext, "updateCorrelationContext");
2415
+ var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
2416
+ function generateCorrelationId() {
2417
+ return randomUUID();
2418
+ }
2419
+ __name(generateCorrelationId, "generateCorrelationId");
2420
+ function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
2421
+ if (typeof reply.header === "function") {
2422
+ reply.header(headerName, correlationId);
2423
+ } else if (reply.raw && typeof reply.raw.setHeader === "function") {
2424
+ reply.raw.setHeader(headerName, correlationId);
2425
+ }
2426
+ }
2427
+ __name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
2428
+
2429
+ // src/logger/services/logger.service.ts
2430
+ function _ts_decorate14(decorators, target, key, desc) {
2431
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2432
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2433
+ 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;
2434
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2435
+ }
2436
+ __name(_ts_decorate14, "_ts_decorate");
2437
+ function _ts_metadata8(k, v) {
2438
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2439
+ }
2440
+ __name(_ts_metadata8, "_ts_metadata");
2441
+ function _ts_param4(paramIndex, decorator) {
2442
+ return function(target, key) {
2443
+ decorator(target, key, paramIndex);
2444
+ };
2445
+ }
2446
+ __name(_ts_param4, "_ts_param");
2447
+ var LoggerService2 = class _LoggerService {
2448
+ static {
2449
+ __name(this, "LoggerService");
2450
+ }
2451
+ defaultLogger;
2452
+ activeLogger;
2453
+ options;
2454
+ context;
2455
+ constructor(options = {}, defaultLogger) {
2456
+ this.defaultLogger = defaultLogger;
2457
+ this.options = options;
2458
+ const provider = options.provider ?? "winston";
2459
+ if (provider === "default") {
2460
+ if (!this.defaultLogger) {
2461
+ throw new Error("LoggerService: Default Logger not provided");
2462
+ }
2463
+ this.activeLogger = this.defaultLogger;
2464
+ } else {
2465
+ this.activeLogger = this.createWinstonLogger(options);
2466
+ }
2467
+ }
2468
+ /**
2469
+ * Creates a Winston logger instance with inline configuration.
2470
+ * Consolidates winston-config.factory.ts logic.
2471
+ */
2472
+ createWinstonLogger(opts) {
2473
+ const level = opts.level ?? "debug";
2474
+ const logFormat = opts.format ?? "text";
2475
+ const baseFormatters = [
2476
+ format.timestamp({
2477
+ format: "YYYY-MM-DDTHH:mm:ss.SSSZ"
2478
+ }),
2479
+ format.errors({
2480
+ stack: true
2481
+ })
2482
+ ];
2483
+ const consoleTransport = logFormat === "json" ? new transports.Console({
2484
+ level,
2485
+ format: format.combine(...baseFormatters, format.json())
2486
+ }) : new transports.Console({
2487
+ level,
2488
+ format: format.combine(...baseFormatters, format.printf((info) => {
2489
+ const { timestamp, level: level2, message, context, correlationId, trace } = info;
2490
+ const parts = [
2491
+ timestamp,
2492
+ level2.toUpperCase().padEnd(7),
2493
+ correlationId ? `[${correlationId.toString().slice(-6)}]` : "",
2494
+ context ? `[${context}]` : "",
2495
+ message
2496
+ ].filter(Boolean);
2497
+ let output = parts.join(" ");
2498
+ if (trace) {
2499
+ output += "\n" + trace;
2500
+ }
2501
+ return output;
2502
+ }), format.colorize({
2503
+ all: true
2504
+ }))
2505
+ });
2506
+ const winstonTransports = [
2507
+ consoleTransport
2508
+ ];
2509
+ if (opts.enableFileLogger) {
2510
+ const filePath = opts.filePath ?? "./logs";
2511
+ const maxFiles = opts.maxFiles ?? "14d";
2512
+ winstonTransports.push(new DailyRotateFile({
2513
+ level,
2514
+ filename: `${filePath}/%DATE%-combined.log`,
2515
+ datePattern: "YYYY-MM-DD",
2516
+ maxSize: "20m",
2517
+ maxFiles,
2518
+ format: format.combine(format.timestamp(), format.json())
2519
+ }), new DailyRotateFile({
2520
+ level: "error",
2521
+ filename: `${filePath}/%DATE%-error.log`,
2522
+ datePattern: "YYYY-MM-DD",
2523
+ maxSize: "20m",
2524
+ maxFiles,
2525
+ format: format.combine(format.timestamp(), format.json())
2526
+ }));
2527
+ }
2528
+ const config = {
2529
+ level,
2530
+ transports: winstonTransports,
2531
+ exitOnError: false
2532
+ };
2533
+ if (opts.defaultMeta || opts.appName) {
2534
+ config.defaultMeta = {
2535
+ ...opts.defaultMeta,
2536
+ appName: opts.appName,
2537
+ environment: opts.environment
2538
+ };
2539
+ }
2540
+ return createLogger(config);
2541
+ }
2542
+ // NestJS LoggerService interface methods
2543
+ log(message, context) {
2544
+ this._log("log", message, context);
2545
+ }
2546
+ error(message, trace, context) {
2547
+ this._log("error", message, context, trace);
2548
+ }
2549
+ warn(message, context) {
2550
+ this._log("warn", message, context);
2551
+ }
2552
+ debug(message, context) {
2553
+ this._log("debug", message, context);
2554
+ }
2555
+ verbose(message, context) {
2556
+ this._log("verbose", message, context);
2557
+ }
2558
+ setContext(context) {
2559
+ this.context = context;
2560
+ }
2561
+ /**
2562
+ * Unified internal logging method that handles both Winston and NestJS Logger.
2563
+ */
2564
+ _log(level, message, context, trace) {
2565
+ const ctx = context ?? this.context;
2566
+ if ("format" in this.activeLogger && "transports" in this.activeLogger) {
2567
+ const winstonLogger = this.activeLogger;
2568
+ const winstonLevel = level === "log" ? "info" : level;
2569
+ const formattedMessage = this.formatMessage(message);
2570
+ const metadata = this.enrichMetadata({}, ctx, trace);
2571
+ winstonLogger.log({
2572
+ level: winstonLevel,
2573
+ message: formattedMessage,
2574
+ ...metadata
2575
+ });
2576
+ } else {
2577
+ const nestLogger = this.activeLogger;
2578
+ if (level === "error" && trace) {
2579
+ ctx ? nestLogger.error(message, trace, ctx) : nestLogger.error(message, trace);
2580
+ } else if (level === "log") {
2581
+ ctx ? nestLogger.log(message, ctx) : nestLogger.log(message);
2582
+ } else if (level === "warn") {
2583
+ ctx ? nestLogger.warn(message, ctx) : nestLogger.warn(message);
2584
+ } else if (level === "debug" && nestLogger.debug) {
2585
+ ctx ? nestLogger.debug(message, ctx) : nestLogger.debug(message);
2586
+ } else if (level === "verbose" && nestLogger.verbose) {
2587
+ ctx ? nestLogger.verbose(message, ctx) : nestLogger.verbose(message);
2588
+ }
2589
+ }
2590
+ }
2591
+ /**
2592
+ * Logs with custom metadata (Winston only).
2593
+ */
2594
+ logWithMetadata(level, message, metadata, context) {
2595
+ const ctx = context ?? this.context;
2596
+ if ("format" in this.activeLogger && "transports" in this.activeLogger) {
2597
+ const winstonLogger = this.activeLogger;
2598
+ const winstonLevel = level === "log" ? "info" : level;
2599
+ winstonLogger.log({
2600
+ level: winstonLevel,
2601
+ message: this.formatMessage(message),
2602
+ ...metadata
2603
+ });
2604
+ } else {
2605
+ const messageWithMeta = metadata ? `${message} ${JSON.stringify(metadata)}` : message;
2606
+ this[level](messageWithMeta, ctx);
2607
+ }
2608
+ }
2609
+ formatMessage(message) {
2610
+ if (message instanceof Error) return message.message;
2611
+ if (typeof message === "object" && message !== null) {
2612
+ try {
2613
+ return JSON.stringify(message);
2614
+ } catch {
2615
+ return String(message);
2616
+ }
2617
+ }
2618
+ return String(message);
2619
+ }
2620
+ /**
2621
+ * Enriches metadata with correlation context from AsyncLocalStorage.
2622
+ * Inline from winston-logger.service.ts
2623
+ */
2624
+ enrichMetadata(metadata = {}, context, trace) {
2625
+ const enriched = {
2626
+ ...metadata
2627
+ };
2628
+ if (context) enriched.context = context;
2629
+ const correlationContext = getCorrelationContext();
2630
+ if (correlationContext) {
2631
+ if (correlationContext.correlationId) enriched.correlationId = correlationContext.correlationId;
2632
+ for (const [key, value] of Object.entries(correlationContext)) {
2633
+ if (key !== "correlationId") {
2634
+ enriched[key] = value;
2635
+ }
2636
+ }
2637
+ }
2638
+ if (trace) enriched.trace = trace;
2639
+ return enriched;
2640
+ }
2641
+ child(context) {
2642
+ const childLogger = new _LoggerService(this.options, this.defaultLogger);
2643
+ childLogger.setContext(context);
2644
+ return childLogger;
2645
+ }
2646
+ };
2647
+ LoggerService2 = _ts_decorate14([
2648
+ Injectable9(),
2649
+ _ts_param4(0, Optional()),
2650
+ _ts_param4(1, Optional()),
2651
+ _ts_metadata8("design:type", Function),
2652
+ _ts_metadata8("design:paramtypes", [
2653
+ typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
2654
+ typeof Logger10 === "undefined" ? Object : Logger10
2655
+ ])
2656
+ ], LoggerService2);
2657
+
2658
+ // src/logger/middleware/correlation-id.middleware.ts
2659
+ import { Injectable as Injectable10 } from "@nestjs/common";
2660
+ function _ts_decorate15(decorators, target, key, desc) {
2661
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2662
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2663
+ 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;
2664
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2665
+ }
2666
+ __name(_ts_decorate15, "_ts_decorate");
2667
+ function _ts_metadata9(k, v) {
2668
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2669
+ }
2670
+ __name(_ts_metadata9, "_ts_metadata");
2671
+ var CorrelationIdMiddleware = class {
2672
+ static {
2673
+ __name(this, "CorrelationIdMiddleware");
2674
+ }
2675
+ includeInResponse;
2676
+ responseHeader;
2677
+ constructor(options = {}) {
2678
+ this.includeInResponse = options.includeInResponse ?? true;
2679
+ this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
2680
+ }
2681
+ /**
2682
+ * Middleware handler for processing requests.
2683
+ */
2684
+ use(req, reply, next) {
2685
+ const correlationId = generateCorrelationId();
2686
+ if (this.includeInResponse) {
2687
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2688
+ }
2689
+ runWithCorrelationContext({
2690
+ correlationId
2691
+ }, () => {
2692
+ next();
2693
+ });
2694
+ }
2695
+ /**
2696
+ * Fastify hook handler for onRequest.
2697
+ * This is an async function that returns a Promise, ensuring the AsyncLocalStorage
2698
+ * context persists throughout the entire request lifecycle.
2699
+ */
2700
+ async onRequest(req, reply) {
2701
+ const correlationId = generateCorrelationId();
2702
+ if (this.includeInResponse) {
2703
+ addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
2704
+ }
2705
+ const store = correlationStorage.getStore();
2706
+ if (!store) {
2707
+ correlationStorage.enterWith({
2708
+ correlationId
2709
+ });
2710
+ }
2711
+ }
2712
+ };
2713
+ CorrelationIdMiddleware = _ts_decorate15([
2714
+ Injectable10(),
2715
+ _ts_metadata9("design:type", Function),
2716
+ _ts_metadata9("design:paramtypes", [
2717
+ typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
2718
+ ])
2719
+ ], CorrelationIdMiddleware);
2720
+
2721
+ // src/logger/interceptors/http-logger.interceptor.ts
2722
+ import { Injectable as Injectable11, Optional as Optional2 } from "@nestjs/common";
2723
+ import { tap as tap2, catchError } from "rxjs/operators";
2724
+ function _ts_decorate16(decorators, target, key, desc) {
2725
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2726
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2727
+ 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;
2728
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2729
+ }
2730
+ __name(_ts_decorate16, "_ts_decorate");
2731
+ function _ts_metadata10(k, v) {
2732
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2733
+ }
2734
+ __name(_ts_metadata10, "_ts_metadata");
2735
+ function _ts_param5(paramIndex, decorator) {
2736
+ return function(target, key) {
2737
+ decorator(target, key, paramIndex);
2738
+ };
2739
+ }
2740
+ __name(_ts_param5, "_ts_param");
2741
+ var HttpLoggerInterceptor = class {
2742
+ static {
2743
+ __name(this, "HttpLoggerInterceptor");
2744
+ }
2745
+ logger;
2746
+ enableRequestLog;
2747
+ enableResponseLog;
2748
+ slowRequestThreshold;
2749
+ constructor(logger, options) {
2750
+ this.logger = logger;
2751
+ this.enableRequestLog = options?.enableRequestLog ?? true;
2752
+ this.enableResponseLog = options?.enableResponseLog ?? true;
2753
+ this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
2754
+ }
2755
+ intercept(context, next) {
2756
+ if (context.getType() !== "http") {
2757
+ return next.handle();
2758
+ }
2759
+ const httpContext = context.switchToHttp();
2760
+ const request = httpContext.getRequest();
2761
+ const response = httpContext.getResponse();
2762
+ const startTime = Date.now();
2763
+ if (this.enableRequestLog) {
2764
+ this.logRequest(request);
2765
+ }
2766
+ return next.handle().pipe(tap2(() => {
2767
+ if (this.enableResponseLog) {
2768
+ const duration = Date.now() - startTime;
2769
+ this.logResponse(request, response, duration);
2770
+ }
2771
+ }), catchError((error) => {
2772
+ const duration = Date.now() - startTime;
2773
+ this.logError(request, response, duration, error);
2774
+ throw error;
2775
+ }));
2776
+ }
2777
+ logRequest(request) {
2778
+ try {
2779
+ const correlationContext = getCorrelationContext();
2780
+ const metadata = {
2781
+ type: "http_request",
2782
+ method: request.method,
2783
+ url: request.url,
2784
+ correlationId: correlationContext?.correlationId,
2785
+ ip: request.ip,
2786
+ userAgent: request.headers["user-agent"]
2787
+ };
2788
+ this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
2789
+ } catch (error) {
2790
+ this.logger.error("Failed to log HTTP request", error.stack);
2791
+ }
2792
+ }
2793
+ logResponse(request, response, duration) {
2794
+ try {
2795
+ const correlationContext = getCorrelationContext();
2796
+ const statusCode = response.statusCode;
2797
+ const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
2798
+ const metadata = {
2799
+ type: "http_response",
2800
+ method: request.method,
2801
+ url: request.url,
2802
+ statusCode,
2803
+ duration,
2804
+ correlationId: correlationContext?.correlationId
2805
+ };
2806
+ if (duration > this.slowRequestThreshold) {
2807
+ metadata.slowRequest = true;
2808
+ }
2809
+ const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
2810
+ this.logger.logWithMetadata(logLevel, message, metadata);
2811
+ } catch (error) {
2812
+ this.logger.error("Failed to log HTTP response", error.stack);
2813
+ }
2814
+ }
2815
+ logError(request, response, duration, error) {
2816
+ try {
2817
+ const correlationContext = getCorrelationContext();
2818
+ const statusCode = response.statusCode || 500;
2819
+ const metadata = {
2820
+ type: "http_error",
2821
+ method: request.method,
2822
+ url: request.url,
2823
+ statusCode,
2824
+ duration,
2825
+ correlationId: correlationContext?.correlationId,
2826
+ errorName: error?.name || "Error",
2827
+ errorMessage: error?.message || "Unknown error"
2828
+ };
2829
+ if (error?.stack) {
2830
+ metadata.trace = error.stack;
2831
+ }
2832
+ if (error?.response) {
2833
+ metadata.errorDetails = error.response;
2834
+ }
2835
+ const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
2836
+ this.logger.logWithMetadata("error", message, metadata);
2837
+ } catch (loggingError) {
2838
+ this.logger.error("Failed to log HTTP error", loggingError.stack);
2839
+ }
2840
+ }
2841
+ };
2842
+ HttpLoggerInterceptor = _ts_decorate16([
2843
+ Injectable11(),
2844
+ _ts_param5(1, Optional2()),
2845
+ _ts_metadata10("design:type", Function),
2846
+ _ts_metadata10("design:paramtypes", [
2847
+ typeof LoggerService === "undefined" ? Object : LoggerService,
2848
+ typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
2849
+ ])
2850
+ ], HttpLoggerInterceptor);
2851
+
2852
+ // src/logger/logger.module.ts
2853
+ function _ts_decorate17(decorators, target, key, desc) {
2854
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2855
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2856
+ 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;
2857
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2858
+ }
2859
+ __name(_ts_decorate17, "_ts_decorate");
2860
+ var LOGGER_MODULE_OPTIONS = Symbol("LOGGER_MODULE_OPTIONS");
2861
+ var DEFAULT_LOGGER_OPTIONS = {
2862
+ provider: "winston",
2863
+ enableCorrelationId: true,
2864
+ enableHttpLogger: true,
2865
+ filePath: "./logs",
2866
+ maxFiles: "14d"
2867
+ };
2868
+ var ENVIRONMENT_PRESETS = {
2869
+ /**
2870
+ * Development preset - maximum verbosity for local development
2871
+ */
2872
+ development: {
2873
+ provider: "winston",
2874
+ level: "debug",
2875
+ format: "text",
2876
+ enableFileLogger: false,
2877
+ enableCorrelationId: true,
2878
+ enableHttpLogger: true,
2879
+ httpLogger: {
2880
+ enableRequestLog: true,
2881
+ enableResponseLog: true,
2882
+ slowRequestThreshold: 1e3
2883
+ }
2884
+ },
2885
+ /**
2886
+ * Staging preset - moderate verbosity with file logging
2887
+ */
2888
+ staging: {
2889
+ provider: "winston",
2890
+ level: "log",
2891
+ format: "json",
2892
+ enableFileLogger: true,
2893
+ enableCorrelationId: true,
2894
+ enableHttpLogger: true,
2895
+ httpLogger: {
2896
+ enableRequestLog: true,
2897
+ enableResponseLog: true,
2898
+ slowRequestThreshold: 3e3
2899
+ }
2900
+ },
2901
+ /**
2902
+ * Production preset - minimal verbosity with all safety features enabled
2903
+ */
2904
+ production: {
2905
+ provider: "winston",
2906
+ level: "warn",
2907
+ format: "json",
2908
+ enableFileLogger: true,
2909
+ enableCorrelationId: true,
2910
+ enableHttpLogger: true,
2911
+ httpLogger: {
2912
+ enableRequestLog: false,
2913
+ enableResponseLog: true,
2914
+ slowRequestThreshold: 5e3
2915
+ }
2916
+ },
2917
+ /**
2918
+ * Test preset - errors only, minimal features for faster test execution
2919
+ */
2920
+ test: {
2921
+ provider: "winston",
2922
+ level: "error",
2923
+ format: "json",
2924
+ enableFileLogger: false,
2925
+ enableCorrelationId: false,
2926
+ enableHttpLogger: false
2927
+ }
2928
+ };
2929
+ function mergeWithDefaults(options = {}) {
2930
+ const preset = options.environment ? ENVIRONMENT_PRESETS[options.environment] ?? ENVIRONMENT_PRESETS.development : ENVIRONMENT_PRESETS.development;
2931
+ const filteredOptions = Object.fromEntries(Object.entries(options).filter(([_, value]) => value !== void 0));
2932
+ if (filteredOptions.httpLogger && preset?.httpLogger) {
2933
+ filteredOptions.httpLogger = {
2934
+ ...preset.httpLogger,
2935
+ ...Object.fromEntries(Object.entries(filteredOptions.httpLogger).filter(([_, value]) => value !== void 0))
2936
+ };
2937
+ }
2938
+ const merged = {
2939
+ ...DEFAULT_LOGGER_OPTIONS,
2940
+ ...preset,
2941
+ ...filteredOptions
2942
+ };
2943
+ return merged;
2944
+ }
2945
+ __name(mergeWithDefaults, "mergeWithDefaults");
2946
+ function createDefaultLoggerProvider(options) {
2947
+ return {
2948
+ provide: Logger11,
2949
+ useFactory: /* @__PURE__ */ __name(() => {
2950
+ const logger = new Logger11();
2951
+ if (options.level && typeof logger.setLogLevels === "function") {
2952
+ const levels = getLevelsUpTo(options.level);
2953
+ logger.setLogLevels(levels);
2954
+ }
2955
+ return logger;
2956
+ }, "useFactory")
2957
+ };
2958
+ }
2959
+ __name(createDefaultLoggerProvider, "createDefaultLoggerProvider");
2960
+ function createLoggerProviders(options = {}) {
2961
+ const mergedOptions = mergeWithDefaults(options);
2962
+ const providers = [
2963
+ // Options provider
2964
+ {
2965
+ provide: LOGGER_MODULE_OPTIONS,
2966
+ useValue: mergedOptions
2967
+ }
2968
+ ];
2969
+ if (mergedOptions.provider === "default") {
2970
+ providers.push(createDefaultLoggerProvider(mergedOptions));
2971
+ }
2972
+ providers.push({
2973
+ provide: LoggerService2,
2974
+ useFactory: /* @__PURE__ */ __name((opts, defaultLogger) => {
2975
+ return new LoggerService2(opts, defaultLogger);
2976
+ }, "useFactory"),
2977
+ inject: [
2978
+ LOGGER_MODULE_OPTIONS,
2979
+ {
2980
+ token: Logger11,
2981
+ optional: true
2982
+ }
2983
+ ]
2984
+ });
2985
+ providers.push({
2986
+ provide: CorrelationIdMiddleware,
2987
+ useFactory: /* @__PURE__ */ __name(() => {
2988
+ return new CorrelationIdMiddleware({
2989
+ includeInResponse: true,
2990
+ responseHeader: "x-correlation-id"
2991
+ });
2992
+ }, "useFactory")
2993
+ });
2994
+ providers.push({
2995
+ provide: HttpLoggerInterceptor,
2996
+ useFactory: /* @__PURE__ */ __name((logger, opts) => {
2997
+ const httpLoggerOptions = opts.httpLogger ?? {
2998
+ enableRequestLog: opts.enableHttpLogger,
2999
+ enableResponseLog: opts.enableHttpLogger
3000
+ };
3001
+ return new HttpLoggerInterceptor(logger, httpLoggerOptions);
3002
+ }, "useFactory"),
3003
+ inject: [
3004
+ LoggerService2,
3005
+ LOGGER_MODULE_OPTIONS
3006
+ ]
3007
+ });
3008
+ return providers;
3009
+ }
3010
+ __name(createLoggerProviders, "createLoggerProviders");
3011
+ function getLevelsUpTo(level) {
3012
+ const allLevels = [
3013
+ "error",
3014
+ "warn",
3015
+ "log",
3016
+ "debug",
3017
+ "verbose"
3018
+ ];
3019
+ const isValidLevel = /* @__PURE__ */ __name((l) => allLevels.includes(l), "isValidLevel");
3020
+ if (!isValidLevel(level)) {
3021
+ return [
3022
+ "error",
3023
+ "warn",
3024
+ "log"
3025
+ ];
3026
+ }
3027
+ const levelIndex = allLevels.indexOf(level);
3028
+ return allLevels.slice(0, levelIndex + 1);
3029
+ }
3030
+ __name(getLevelsUpTo, "getLevelsUpTo");
3031
+ var LoggerModule = class _LoggerModule {
3032
+ static {
3033
+ __name(this, "LoggerModule");
3034
+ }
3035
+ /**
3036
+ * Configures the logger module with static options.
3037
+ *
3038
+ * Users must explicitly pass `environment` to select a preset.
3039
+ * All preset values can be overridden by passing explicit options.
3040
+ *
3041
+ * @param options - Logger configuration options
3042
+ * @returns Dynamic module configuration
3043
+ *
3044
+ * @example
3045
+ * ```typescript
3046
+ * // Production preset with app name
3047
+ * LoggerModule.forRoot({
3048
+ * environment: 'production',
3049
+ * appName: 'my-service'
3050
+ * })
3051
+ *
3052
+ * // Development preset with custom level
3053
+ * LoggerModule.forRoot({
3054
+ * environment: 'development',
3055
+ * level: 'verbose',
3056
+ * enableFileLogger: true
3057
+ * })
3058
+ *
3059
+ * // Use default NestJS logger
3060
+ * LoggerModule.forRoot({
3061
+ * provider: 'default',
3062
+ * environment: 'development'
3063
+ * })
3064
+ * ```
3065
+ */
3066
+ static forRoot(options = {}) {
3067
+ const providers = createLoggerProviders(options);
3068
+ return {
3069
+ module: _LoggerModule,
3070
+ providers,
3071
+ exports: [
3072
+ LoggerService2,
3073
+ CorrelationIdMiddleware,
3074
+ HttpLoggerInterceptor,
3075
+ LOGGER_MODULE_OPTIONS
3076
+ ]
3077
+ };
3078
+ }
3079
+ /**
3080
+ * Configures the logger module with async options.
3081
+ *
3082
+ * Supports dynamic configuration using:
3083
+ * - `useFactory`: Factory function with dependency injection
3084
+ * - `useClass`: Class implementing `LoggerOptionsFactory`
3085
+ * - `useExisting`: Existing provider implementing `LoggerOptionsFactory`
3086
+ *
3087
+ * Options from the factory/class are merged with environment preset defaults.
3088
+ *
3089
+ * @param options - Async configuration options
3090
+ * @returns Dynamic module configuration
3091
+ *
3092
+ * @example
3093
+ * ```typescript
3094
+ * // Factory with ConfigService
3095
+ * LoggerModule.forRootAsync({
3096
+ * imports: [ConfigModule],
3097
+ * useFactory: (config: ConfigService) => ({
3098
+ * environment: config.get('NODE_ENV', 'development'),
3099
+ * provider: config.get('LOG_PROVIDER', 'winston'),
3100
+ * level: config.get('LOG_LEVEL'),
3101
+ * appName: config.get('APP_NAME'),
3102
+ * }),
3103
+ * inject: [ConfigService]
3104
+ * })
3105
+ *
3106
+ * // Factory class
3107
+ * @Injectable()
3108
+ * class LoggerConfigService implements LoggerOptionsFactory {
3109
+ * createLoggerOptions(): LoggerModuleOptions {
3110
+ * return {
3111
+ * environment: 'production',
3112
+ * appName: 'my-service'
3113
+ * };
3114
+ * }
3115
+ * }
3116
+ *
3117
+ * LoggerModule.forRootAsync({
3118
+ * useClass: LoggerConfigService
3119
+ * })
3120
+ * ```
3121
+ */
3122
+ static forRootAsync(options) {
3123
+ const asyncProviders = this.createAsyncProviders(options);
3124
+ return {
3125
+ module: _LoggerModule,
3126
+ imports: options.imports || [],
3127
+ providers: [
3128
+ ...asyncProviders,
3129
+ // Default logger provider
3130
+ {
3131
+ provide: Logger11,
3132
+ useFactory: /* @__PURE__ */ __name((opts) => {
3133
+ if (opts.provider === "default") {
3134
+ const logger = new Logger11();
3135
+ if (opts.level && typeof logger.setLogLevels === "function") {
3136
+ const levels = getLevelsUpTo(opts.level);
3137
+ logger.setLogLevels(levels);
3138
+ }
3139
+ return logger;
3140
+ }
3141
+ return null;
3142
+ }, "useFactory"),
3143
+ inject: [
3144
+ LOGGER_MODULE_OPTIONS
3145
+ ]
3146
+ },
3147
+ // Unified logger service
3148
+ {
3149
+ provide: LoggerService2,
3150
+ useFactory: /* @__PURE__ */ __name((opts, defaultLogger) => {
3151
+ return new LoggerService2(opts, defaultLogger);
3152
+ }, "useFactory"),
3153
+ inject: [
3154
+ LOGGER_MODULE_OPTIONS,
3155
+ {
3156
+ token: Logger11,
3157
+ optional: true
3158
+ }
3159
+ ]
3160
+ },
3161
+ // Correlation ID middleware
3162
+ {
3163
+ provide: CorrelationIdMiddleware,
3164
+ useFactory: /* @__PURE__ */ __name(() => {
3165
+ return new CorrelationIdMiddleware({
3166
+ includeInResponse: true,
3167
+ responseHeader: "x-correlation-id"
3168
+ });
3169
+ }, "useFactory")
3170
+ },
3171
+ // HTTP logger interceptor
3172
+ {
3173
+ provide: HttpLoggerInterceptor,
3174
+ useFactory: /* @__PURE__ */ __name((logger, opts) => {
3175
+ const httpLoggerOptions = opts.httpLogger ?? {
3176
+ enableRequestLog: opts.enableHttpLogger,
3177
+ enableResponseLog: opts.enableHttpLogger
3178
+ };
3179
+ return new HttpLoggerInterceptor(logger, httpLoggerOptions);
3180
+ }, "useFactory"),
3181
+ inject: [
3182
+ LoggerService2,
3183
+ LOGGER_MODULE_OPTIONS
3184
+ ]
3185
+ }
3186
+ ],
3187
+ exports: [
3188
+ LoggerService2,
3189
+ CorrelationIdMiddleware,
3190
+ HttpLoggerInterceptor,
3191
+ LOGGER_MODULE_OPTIONS
3192
+ ]
3193
+ };
3194
+ }
3195
+ /**
3196
+ * Configures middleware for the module.
3197
+ * Middleware is registered globally in main.ts using Fastify hooks.
3198
+ */
3199
+ configure(consumer) {
3200
+ }
3201
+ /**
3202
+ * Creates async providers for dynamic module configuration.
3203
+ */
3204
+ static createAsyncProviders(options) {
3205
+ if (options.useFactory) {
3206
+ return [
3207
+ this.createAsyncOptionsProvider(options)
3208
+ ];
3209
+ }
3210
+ const providers = [
3211
+ this.createAsyncOptionsProvider(options)
3212
+ ];
3213
+ if (options.useClass) {
3214
+ providers.push({
3215
+ provide: options.useClass,
3216
+ useClass: options.useClass
3217
+ });
3218
+ }
3219
+ return providers;
3220
+ }
3221
+ /**
3222
+ * Creates the async options provider.
3223
+ */
3224
+ static createAsyncOptionsProvider(options) {
3225
+ if (options.useFactory) {
3226
+ return {
3227
+ provide: LOGGER_MODULE_OPTIONS,
3228
+ useFactory: /* @__PURE__ */ __name(async (...args) => {
3229
+ const userOptions = await options.useFactory(...args);
3230
+ return mergeWithDefaults(userOptions);
3231
+ }, "useFactory"),
3232
+ inject: options.inject || []
3233
+ };
3234
+ }
3235
+ if (options.useClass) {
3236
+ return {
3237
+ provide: LOGGER_MODULE_OPTIONS,
3238
+ useFactory: /* @__PURE__ */ __name(async (optionsFactory) => {
3239
+ const userOptions = await optionsFactory.createLoggerOptions();
3240
+ return mergeWithDefaults(userOptions);
3241
+ }, "useFactory"),
3242
+ inject: [
3243
+ options.useClass
3244
+ ]
3245
+ };
3246
+ }
3247
+ if (options.useExisting) {
3248
+ return {
3249
+ provide: LOGGER_MODULE_OPTIONS,
3250
+ useFactory: /* @__PURE__ */ __name(async (optionsFactory) => {
3251
+ const userOptions = await optionsFactory.createLoggerOptions();
3252
+ return mergeWithDefaults(userOptions);
3253
+ }, "useFactory"),
3254
+ inject: [
3255
+ options.useExisting
3256
+ ]
3257
+ };
3258
+ }
3259
+ throw new Error("LoggerModule.forRootAsync() requires one of: useFactory, useClass, or useExisting");
3260
+ }
3261
+ };
3262
+ LoggerModule = _ts_decorate17([
3263
+ Global4(),
3264
+ Module5({})
3265
+ ], LoggerModule);
2348
3266
  export {
2349
3267
  AuthConfigModule,
2350
3268
  BadGatewayException,
2351
3269
  BadRequestException,
2352
3270
  BaseFieldException,
2353
3271
  ConflictException,
3272
+ CorrelationIdMiddleware,
2354
3273
  CsrfGuard,
3274
+ DEFAULT_CORRELATION_HEADER,
2355
3275
  DatabaseModule,
2356
3276
  ForbiddenException2 as ForbiddenException,
2357
3277
  GoneException,
2358
3278
  HttpExceptionFilter,
3279
+ HttpLoggerInterceptor,
2359
3280
  HttpModule,
2360
3281
  InternalServerErrorException3 as InternalServerErrorException,
3282
+ LOGGER_MODULE_OPTIONS,
3283
+ LoggerModule,
3284
+ LoggerService2 as LoggerService,
2361
3285
  MethodNotAllowedException,
2362
3286
  NotAcceptableException,
2363
3287
  NotFoundException,
@@ -2379,6 +3303,12 @@ export {
2379
3303
  UnsupportedMediaTypeException,
2380
3304
  ValidationException,
2381
3305
  VrittiAuthGuard,
2382
- getHttpStatusTitle
3306
+ addCorrelationIdToResponse,
3307
+ correlationStorage,
3308
+ generateCorrelationId,
3309
+ getCorrelationContext,
3310
+ getHttpStatusTitle,
3311
+ runWithCorrelationContext,
3312
+ updateCorrelationContext
2383
3313
  };
2384
3314
  //# sourceMappingURL=index.js.map