@vritti/api-sdk 0.1.3 → 0.1.4
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 +696 -686
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +659 -649
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -48,7 +48,7 @@ __export(index_exports, {
|
|
|
48
48
|
InternalServerErrorException: () => InternalServerErrorException3,
|
|
49
49
|
LOGGER_MODULE_OPTIONS: () => LOGGER_MODULE_OPTIONS,
|
|
50
50
|
LoggerModule: () => LoggerModule,
|
|
51
|
-
LoggerService: () =>
|
|
51
|
+
LoggerService: () => LoggerService,
|
|
52
52
|
MethodNotAllowedException: () => MethodNotAllowedException,
|
|
53
53
|
NotAcceptableException: () => NotAcceptableException,
|
|
54
54
|
NotFoundException: () => NotFoundException,
|
|
@@ -56,13 +56,13 @@ __export(index_exports, {
|
|
|
56
56
|
Onboarding: () => Onboarding,
|
|
57
57
|
PayloadTooLargeException: () => PayloadTooLargeException,
|
|
58
58
|
PrimaryBaseRepository: () => PrimaryBaseRepository,
|
|
59
|
-
PrimaryDatabaseService: () =>
|
|
59
|
+
PrimaryDatabaseService: () => PrimaryDatabaseService,
|
|
60
60
|
Public: () => Public,
|
|
61
61
|
RequestTimeoutException: () => RequestTimeoutException,
|
|
62
62
|
ServiceUnavailableException: () => ServiceUnavailableException,
|
|
63
63
|
Tenant: () => Tenant,
|
|
64
64
|
TenantBaseRepository: () => TenantBaseRepository,
|
|
65
|
-
TenantContextService: () =>
|
|
65
|
+
TenantContextService: () => TenantContextService,
|
|
66
66
|
TenantDatabaseService: () => TenantDatabaseService,
|
|
67
67
|
TooManyRequestsException: () => TooManyRequestsException,
|
|
68
68
|
UnauthorizedException: () => UnauthorizedException4,
|
|
@@ -89,10 +89,10 @@ __export(index_exports, {
|
|
|
89
89
|
module.exports = __toCommonJS(index_exports);
|
|
90
90
|
|
|
91
91
|
// src/auth/auth-config.module.ts
|
|
92
|
-
var
|
|
93
|
-
var
|
|
94
|
-
var
|
|
95
|
-
var
|
|
92
|
+
var import_common5 = require("@nestjs/common");
|
|
93
|
+
var import_config4 = require("@nestjs/config");
|
|
94
|
+
var import_core3 = require("@nestjs/core");
|
|
95
|
+
var import_jwt2 = require("@nestjs/jwt");
|
|
96
96
|
|
|
97
97
|
// src/request/request.module.ts
|
|
98
98
|
var import_common2 = require("@nestjs/common");
|
|
@@ -193,7 +193,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
__name(_ts_param, "_ts_param");
|
|
196
|
-
var
|
|
196
|
+
var RequestService = class {
|
|
197
197
|
static {
|
|
198
198
|
__name(this, "RequestService");
|
|
199
199
|
}
|
|
@@ -262,7 +262,7 @@ var RequestService2 = class {
|
|
|
262
262
|
return this.request.headers || {};
|
|
263
263
|
}
|
|
264
264
|
};
|
|
265
|
-
|
|
265
|
+
RequestService = _ts_decorate([
|
|
266
266
|
(0, import_common.Injectable)({
|
|
267
267
|
scope: import_common.Scope.REQUEST
|
|
268
268
|
}),
|
|
@@ -271,7 +271,7 @@ RequestService2 = _ts_decorate([
|
|
|
271
271
|
_ts_metadata("design:paramtypes", [
|
|
272
272
|
typeof FastifyRequest === "undefined" ? Object : FastifyRequest
|
|
273
273
|
])
|
|
274
|
-
],
|
|
274
|
+
], RequestService);
|
|
275
275
|
|
|
276
276
|
// src/request/request.module.ts
|
|
277
277
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
@@ -290,16 +290,256 @@ RequestModule = _ts_decorate2([
|
|
|
290
290
|
(0, import_common2.Global)(),
|
|
291
291
|
(0, import_common2.Module)({
|
|
292
292
|
providers: [
|
|
293
|
-
|
|
293
|
+
RequestService
|
|
294
294
|
],
|
|
295
295
|
exports: [
|
|
296
|
-
|
|
296
|
+
RequestService
|
|
297
297
|
]
|
|
298
298
|
})
|
|
299
299
|
], RequestModule);
|
|
300
300
|
|
|
301
301
|
// src/auth/guards/vritti-auth.guard.ts
|
|
302
|
+
var import_common4 = require("@nestjs/common");
|
|
303
|
+
var import_config2 = require("@nestjs/config");
|
|
304
|
+
var import_core2 = require("@nestjs/core");
|
|
305
|
+
var import_jwt = require("@nestjs/jwt");
|
|
306
|
+
|
|
307
|
+
// src/database/services/primary-database.service.ts
|
|
302
308
|
var import_common3 = require("@nestjs/common");
|
|
309
|
+
var import_drizzle_orm = require("drizzle-orm");
|
|
310
|
+
var import_node_postgres = require("drizzle-orm/node-postgres");
|
|
311
|
+
var import_pg = require("pg");
|
|
312
|
+
|
|
313
|
+
// src/database/constants.ts
|
|
314
|
+
var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
|
|
315
|
+
|
|
316
|
+
// src/database/services/primary-database.service.ts
|
|
317
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
318
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
319
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
320
|
+
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;
|
|
321
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
322
|
+
}
|
|
323
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
324
|
+
function _ts_metadata2(k, v) {
|
|
325
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
326
|
+
}
|
|
327
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
328
|
+
function _ts_param2(paramIndex, decorator) {
|
|
329
|
+
return function(target, key) {
|
|
330
|
+
decorator(target, key, paramIndex);
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
__name(_ts_param2, "_ts_param");
|
|
334
|
+
var PrimaryDatabaseService = class _PrimaryDatabaseService {
|
|
335
|
+
static {
|
|
336
|
+
__name(this, "PrimaryDatabaseService");
|
|
337
|
+
}
|
|
338
|
+
options;
|
|
339
|
+
logger = new import_common3.Logger(_PrimaryDatabaseService.name);
|
|
340
|
+
/** PostgreSQL connection pool */
|
|
341
|
+
pool = null;
|
|
342
|
+
/** Drizzle database instance */
|
|
343
|
+
db = null;
|
|
344
|
+
/** In-memory cache: Map<tenantIdentifier, TenantConfig> */
|
|
345
|
+
tenantConfigCache = /* @__PURE__ */ new Map();
|
|
346
|
+
/** Cache TTL in milliseconds */
|
|
347
|
+
cacheTTL;
|
|
348
|
+
constructor(options) {
|
|
349
|
+
this.options = options;
|
|
350
|
+
this.cacheTTL = options.connectionCacheTTL || 3e5;
|
|
351
|
+
}
|
|
352
|
+
async onModuleInit() {
|
|
353
|
+
if (this.options.primaryDb) {
|
|
354
|
+
await this.initializeDrizzleClient();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Initialize connection to primary database using Drizzle
|
|
359
|
+
*/
|
|
360
|
+
async initializeDrizzleClient() {
|
|
361
|
+
try {
|
|
362
|
+
const databaseUrl = this.buildPrimaryDbUrl();
|
|
363
|
+
this.pool = new import_pg.Pool({
|
|
364
|
+
connectionString: databaseUrl,
|
|
365
|
+
max: this.options.maxConnections || 10
|
|
366
|
+
});
|
|
367
|
+
this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
|
|
368
|
+
this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
|
|
369
|
+
this.db = (0, import_node_postgres.drizzle)({
|
|
370
|
+
client: this.pool,
|
|
371
|
+
schema: this.options.drizzleSchema,
|
|
372
|
+
relations: this.options.drizzleRelations
|
|
373
|
+
});
|
|
374
|
+
this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
|
|
375
|
+
await this.pool.query("SELECT 1");
|
|
376
|
+
this.logger.log("Connected to primary database (tenant registry)");
|
|
377
|
+
} catch (error) {
|
|
378
|
+
this.logger.error("Failed to connect to primary database", error);
|
|
379
|
+
throw new import_common3.InternalServerErrorException("Failed to initialize tenant registry");
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Build connection URL from primary database properties
|
|
384
|
+
*/
|
|
385
|
+
buildPrimaryDbUrl() {
|
|
386
|
+
if (!this.options.primaryDb) {
|
|
387
|
+
throw new Error("Primary database configuration not provided");
|
|
388
|
+
}
|
|
389
|
+
const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
|
|
390
|
+
let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
|
|
391
|
+
const params = new URLSearchParams();
|
|
392
|
+
if (schema) {
|
|
393
|
+
params.set("schema", schema);
|
|
394
|
+
}
|
|
395
|
+
params.set("sslmode", sslMode);
|
|
396
|
+
const queryString = params.toString();
|
|
397
|
+
if (queryString) {
|
|
398
|
+
url += `?${queryString}`;
|
|
399
|
+
}
|
|
400
|
+
this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
|
|
401
|
+
return url;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Mask password in connection URL for logging
|
|
405
|
+
*/
|
|
406
|
+
maskPassword(url) {
|
|
407
|
+
return url.replace(/:([^@]+)@/, ":****@");
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Get tenant configuration by identifier (ID or subdomain)
|
|
411
|
+
*
|
|
412
|
+
* @param tenantIdentifier Tenant ID or subdomain
|
|
413
|
+
* @returns Tenant configuration or null if not found
|
|
414
|
+
*/
|
|
415
|
+
async getTenantInfo(tenantIdentifier) {
|
|
416
|
+
const cached = this.tenantConfigCache.get(tenantIdentifier);
|
|
417
|
+
if (cached) {
|
|
418
|
+
this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
|
|
419
|
+
return cached;
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
if (!this.db) {
|
|
423
|
+
throw new Error("Primary database client not initialized");
|
|
424
|
+
}
|
|
425
|
+
this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
|
|
426
|
+
const schema = this.options.drizzleSchema;
|
|
427
|
+
const { tenants, tenantDatabaseConfigs } = schema;
|
|
428
|
+
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);
|
|
429
|
+
if (!result.length) {
|
|
430
|
+
this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
const row = result[0];
|
|
434
|
+
const tenant = row.tenants;
|
|
435
|
+
const config = row.tenant_database_configs;
|
|
436
|
+
if (tenant.status !== "ACTIVE") {
|
|
437
|
+
this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
const info = {
|
|
441
|
+
id: tenant.id,
|
|
442
|
+
subdomain: tenant.subdomain,
|
|
443
|
+
type: tenant.dbType,
|
|
444
|
+
status: tenant.status,
|
|
445
|
+
// For SHARED tenants: schema name
|
|
446
|
+
schemaName: config?.dbSchema || void 0,
|
|
447
|
+
// For DEDICATED tenants: database configuration from TenantDatabaseConfig table
|
|
448
|
+
databaseName: config?.dbName || void 0,
|
|
449
|
+
databaseHost: config?.dbHost || void 0,
|
|
450
|
+
databasePort: config?.dbPort || void 0,
|
|
451
|
+
databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
|
|
452
|
+
databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
|
|
453
|
+
databaseSslMode: config?.dbSslMode || void 0,
|
|
454
|
+
connectionPoolSize: config?.connectionPoolSize || void 0
|
|
455
|
+
};
|
|
456
|
+
this.cacheInfo(info);
|
|
457
|
+
return info;
|
|
458
|
+
} catch (error) {
|
|
459
|
+
this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
|
|
460
|
+
throw new import_common3.InternalServerErrorException("Failed to resolve tenant");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Cache tenant information with TTL
|
|
465
|
+
*/
|
|
466
|
+
cacheInfo(info) {
|
|
467
|
+
this.tenantConfigCache.set(info.id, info);
|
|
468
|
+
this.tenantConfigCache.set(info.subdomain, info);
|
|
469
|
+
setTimeout(() => {
|
|
470
|
+
this.tenantConfigCache.delete(info.id);
|
|
471
|
+
this.tenantConfigCache.delete(info.subdomain);
|
|
472
|
+
this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
|
|
473
|
+
}, this.cacheTTL);
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Clear cached tenant information
|
|
477
|
+
*
|
|
478
|
+
* Useful when tenant settings are updated and cache needs to be invalidated
|
|
479
|
+
*
|
|
480
|
+
* @param tenantIdentifier Tenant ID or subdomain
|
|
481
|
+
*/
|
|
482
|
+
clearTenantCache(tenantIdentifier) {
|
|
483
|
+
const config = this.tenantConfigCache.get(tenantIdentifier);
|
|
484
|
+
if (config) {
|
|
485
|
+
this.tenantConfigCache.delete(config.id);
|
|
486
|
+
this.tenantConfigCache.delete(config.subdomain);
|
|
487
|
+
this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Clear all cached tenant configurations
|
|
492
|
+
*/
|
|
493
|
+
clearAllCaches() {
|
|
494
|
+
const size = this.tenantConfigCache.size;
|
|
495
|
+
this.tenantConfigCache.clear();
|
|
496
|
+
this.logger.log(`Cleared ${size} cached tenant configs`);
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Get the Drizzle database instance for the primary database.
|
|
500
|
+
* This is a synchronous property that returns the initialized Drizzle client.
|
|
501
|
+
*
|
|
502
|
+
* @returns Primary database Drizzle instance
|
|
503
|
+
* @throws Error if primary database client is not initialized
|
|
504
|
+
*/
|
|
505
|
+
get drizzleClient() {
|
|
506
|
+
if (!this.db) {
|
|
507
|
+
throw new Error("Primary database client not initialized");
|
|
508
|
+
}
|
|
509
|
+
return this.db;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get the Drizzle schema
|
|
513
|
+
*/
|
|
514
|
+
get schema() {
|
|
515
|
+
return this.options.drizzleSchema;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Decrypt database credentials
|
|
519
|
+
*
|
|
520
|
+
* Override this method to implement your encryption strategy
|
|
521
|
+
*
|
|
522
|
+
* @param encrypted Encrypted value
|
|
523
|
+
* @returns Decrypted value
|
|
524
|
+
*/
|
|
525
|
+
decrypt(encrypted) {
|
|
526
|
+
return encrypted;
|
|
527
|
+
}
|
|
528
|
+
async onModuleDestroy() {
|
|
529
|
+
if (this.pool) {
|
|
530
|
+
await this.pool.end();
|
|
531
|
+
this.logger.log("Disconnected from primary database");
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
PrimaryDatabaseService = _ts_decorate3([
|
|
536
|
+
(0, import_common3.Injectable)(),
|
|
537
|
+
_ts_param2(0, (0, import_common3.Inject)(DATABASE_MODULE_OPTIONS)),
|
|
538
|
+
_ts_metadata2("design:type", Function),
|
|
539
|
+
_ts_metadata2("design:paramtypes", [
|
|
540
|
+
typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
|
|
541
|
+
])
|
|
542
|
+
], PrimaryDatabaseService);
|
|
303
543
|
|
|
304
544
|
// src/auth/utils/token-hash.util.ts
|
|
305
545
|
var crypto = __toESM(require("crypto"), 1);
|
|
@@ -315,17 +555,17 @@ function verifyTokenHash(token, expectedHash) {
|
|
|
315
555
|
__name(verifyTokenHash, "verifyTokenHash");
|
|
316
556
|
|
|
317
557
|
// src/auth/guards/vritti-auth.guard.ts
|
|
318
|
-
function
|
|
558
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
319
559
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
320
560
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
321
561
|
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;
|
|
322
562
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
323
563
|
}
|
|
324
|
-
__name(
|
|
325
|
-
function
|
|
564
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
565
|
+
function _ts_metadata3(k, v) {
|
|
326
566
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
327
567
|
}
|
|
328
|
-
__name(
|
|
568
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
329
569
|
var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
330
570
|
static {
|
|
331
571
|
__name(this, "VrittiAuthGuard");
|
|
@@ -335,7 +575,7 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
335
575
|
jwtService;
|
|
336
576
|
primaryDatabase;
|
|
337
577
|
requestService;
|
|
338
|
-
logger = new
|
|
578
|
+
logger = new import_common4.Logger(_VrittiAuthGuard.name);
|
|
339
579
|
constructor(reflector, _configService, jwtService, primaryDatabase, requestService) {
|
|
340
580
|
this.reflector = reflector;
|
|
341
581
|
this._configService = _configService;
|
|
@@ -361,17 +601,17 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
361
601
|
const accessToken = this.requestService.getAccessToken();
|
|
362
602
|
if (!accessToken) {
|
|
363
603
|
this.logger.warn("Access token not found in Authorization header");
|
|
364
|
-
throw new
|
|
604
|
+
throw new import_common4.UnauthorizedException("Access token not found");
|
|
365
605
|
}
|
|
366
606
|
const decodedToken = this.jwtService.decode(accessToken);
|
|
367
607
|
if (!decodedToken) {
|
|
368
608
|
this.logger.warn("Failed to decode access token");
|
|
369
|
-
throw new
|
|
609
|
+
throw new import_common4.UnauthorizedException("Invalid token format");
|
|
370
610
|
}
|
|
371
611
|
if (isOnboarding) {
|
|
372
612
|
if (decodedToken.type !== "onboarding") {
|
|
373
613
|
this.logger.warn("Onboarding endpoint requires onboarding token");
|
|
374
|
-
throw new
|
|
614
|
+
throw new import_common4.UnauthorizedException("This endpoint requires an onboarding token");
|
|
375
615
|
}
|
|
376
616
|
const validatedToken2 = this.validateAccessToken(accessToken);
|
|
377
617
|
this.logger.debug("Onboarding token validated successfully");
|
|
@@ -384,7 +624,7 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
384
624
|
}
|
|
385
625
|
if (decodedToken.type === "onboarding") {
|
|
386
626
|
this.logger.warn("Regular endpoint accessed with onboarding token");
|
|
387
|
-
throw new
|
|
627
|
+
throw new import_common4.UnauthorizedException("Onboarding tokens cannot access this endpoint");
|
|
388
628
|
}
|
|
389
629
|
const validatedToken = this.validateAccessToken(accessToken);
|
|
390
630
|
this.logger.debug("Access token validated successfully");
|
|
@@ -396,7 +636,7 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
396
636
|
const tenantIdentifier = this.requestService.getTenantIdentifier();
|
|
397
637
|
if (!tenantIdentifier) {
|
|
398
638
|
this.logger.warn("Tenant identifier not found in request");
|
|
399
|
-
throw new
|
|
639
|
+
throw new import_common4.UnauthorizedException("Tenant identifier not found");
|
|
400
640
|
}
|
|
401
641
|
this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
|
|
402
642
|
if (tenantIdentifier === "cloud") {
|
|
@@ -406,20 +646,20 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
406
646
|
const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
|
|
407
647
|
if (!tenantInfo) {
|
|
408
648
|
this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
|
|
409
|
-
throw new
|
|
649
|
+
throw new import_common4.UnauthorizedException("Invalid tenant");
|
|
410
650
|
}
|
|
411
651
|
if (tenantInfo.status !== "ACTIVE") {
|
|
412
652
|
this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
|
|
413
|
-
throw new
|
|
653
|
+
throw new import_common4.UnauthorizedException(`Tenant is ${tenantInfo.status}`);
|
|
414
654
|
}
|
|
415
655
|
this.logger.debug(`Tenant validated: ${tenantInfo.subdomain} (${tenantInfo.type})`);
|
|
416
656
|
return true;
|
|
417
657
|
} catch (error) {
|
|
418
|
-
if (error instanceof
|
|
658
|
+
if (error instanceof import_common4.UnauthorizedException) {
|
|
419
659
|
throw error;
|
|
420
660
|
}
|
|
421
661
|
this.logger.error("Unexpected error in auth guard", error);
|
|
422
|
-
throw new
|
|
662
|
+
throw new import_common4.UnauthorizedException("Authentication failed");
|
|
423
663
|
}
|
|
424
664
|
}
|
|
425
665
|
/**
|
|
@@ -438,24 +678,24 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
438
678
|
}
|
|
439
679
|
return decoded;
|
|
440
680
|
} catch (error) {
|
|
441
|
-
if (error instanceof
|
|
681
|
+
if (error instanceof import_common4.UnauthorizedException) {
|
|
442
682
|
throw error;
|
|
443
683
|
}
|
|
444
684
|
const jwtError = error;
|
|
445
685
|
if (jwtError?.name === "TokenExpiredError") {
|
|
446
686
|
this.logger.warn(`Access token expired at: ${jwtError?.expiredAt}`);
|
|
447
|
-
throw new
|
|
687
|
+
throw new import_common4.UnauthorizedException("Access token has expired");
|
|
448
688
|
}
|
|
449
689
|
if (jwtError?.name === "JsonWebTokenError") {
|
|
450
690
|
this.logger.warn(`Access token verification failed: ${jwtError?.message}`);
|
|
451
|
-
throw new
|
|
691
|
+
throw new import_common4.UnauthorizedException("Invalid access token");
|
|
452
692
|
}
|
|
453
693
|
if (jwtError?.name === "NotBeforeError") {
|
|
454
694
|
this.logger.warn("Access token used before valid (nbf claim)");
|
|
455
|
-
throw new
|
|
695
|
+
throw new import_common4.UnauthorizedException("Access token not yet valid");
|
|
456
696
|
}
|
|
457
697
|
this.logger.error("Unexpected error validating access token", error);
|
|
458
|
-
throw new
|
|
698
|
+
throw new import_common4.UnauthorizedException("Access token validation failed");
|
|
459
699
|
}
|
|
460
700
|
}
|
|
461
701
|
/**
|
|
@@ -482,37 +722,37 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
482
722
|
const refreshToken = cookies[config.cookie.refreshCookieName];
|
|
483
723
|
if (!refreshToken) {
|
|
484
724
|
this.logger.warn("Session validation failed - refresh token cookie not found");
|
|
485
|
-
throw new
|
|
725
|
+
throw new import_common4.UnauthorizedException("Session validation failed");
|
|
486
726
|
}
|
|
487
727
|
if (!verifyTokenHash(refreshToken, validatedToken.refreshTokenHash)) {
|
|
488
728
|
this.logger.warn("Session validation failed - token binding mismatch");
|
|
489
|
-
throw new
|
|
729
|
+
throw new import_common4.UnauthorizedException("Session validation failed");
|
|
490
730
|
}
|
|
491
731
|
this.logger.debug("Token binding validated successfully");
|
|
492
732
|
}
|
|
493
733
|
};
|
|
494
|
-
VrittiAuthGuard =
|
|
495
|
-
(0,
|
|
496
|
-
scope:
|
|
734
|
+
VrittiAuthGuard = _ts_decorate4([
|
|
735
|
+
(0, import_common4.Injectable)({
|
|
736
|
+
scope: import_common4.Scope.REQUEST
|
|
497
737
|
}),
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
typeof Reflector === "undefined" ? Object : Reflector,
|
|
501
|
-
typeof ConfigService === "undefined" ? Object : ConfigService,
|
|
502
|
-
typeof JwtService === "undefined" ? Object : JwtService,
|
|
738
|
+
_ts_metadata3("design:type", Function),
|
|
739
|
+
_ts_metadata3("design:paramtypes", [
|
|
740
|
+
typeof import_core2.Reflector === "undefined" ? Object : import_core2.Reflector,
|
|
741
|
+
typeof import_config2.ConfigService === "undefined" ? Object : import_config2.ConfigService,
|
|
742
|
+
typeof import_jwt.JwtService === "undefined" ? Object : import_jwt.JwtService,
|
|
503
743
|
typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
|
|
504
744
|
typeof RequestService === "undefined" ? Object : RequestService
|
|
505
745
|
])
|
|
506
746
|
], VrittiAuthGuard);
|
|
507
747
|
|
|
508
748
|
// src/auth/auth-config.module.ts
|
|
509
|
-
function
|
|
749
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
510
750
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
511
751
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
512
752
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
513
753
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
514
754
|
}
|
|
515
|
-
__name(
|
|
755
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
516
756
|
var AuthConfigModule = class _AuthConfigModule {
|
|
517
757
|
static {
|
|
518
758
|
__name(this, "AuthConfigModule");
|
|
@@ -531,14 +771,14 @@ var AuthConfigModule = class _AuthConfigModule {
|
|
|
531
771
|
return {
|
|
532
772
|
module: _AuthConfigModule,
|
|
533
773
|
imports: [
|
|
534
|
-
|
|
774
|
+
import_config4.ConfigModule,
|
|
535
775
|
RequestModule,
|
|
536
|
-
|
|
776
|
+
import_jwt2.JwtModule.registerAsync({
|
|
537
777
|
imports: [
|
|
538
|
-
|
|
778
|
+
import_config4.ConfigModule
|
|
539
779
|
],
|
|
540
780
|
inject: [
|
|
541
|
-
|
|
781
|
+
import_config4.ConfigService
|
|
542
782
|
],
|
|
543
783
|
useFactory: /* @__PURE__ */ __name((config) => ({
|
|
544
784
|
secret: config.get("JWT_SECRET"),
|
|
@@ -550,56 +790,141 @@ var AuthConfigModule = class _AuthConfigModule {
|
|
|
550
790
|
],
|
|
551
791
|
providers: [
|
|
552
792
|
{
|
|
553
|
-
provide:
|
|
793
|
+
provide: import_core3.APP_GUARD,
|
|
554
794
|
useClass: VrittiAuthGuard
|
|
555
795
|
}
|
|
556
796
|
],
|
|
557
797
|
exports: [
|
|
558
|
-
|
|
798
|
+
import_jwt2.JwtModule
|
|
559
799
|
]
|
|
560
800
|
};
|
|
561
801
|
}
|
|
562
802
|
};
|
|
563
|
-
AuthConfigModule =
|
|
564
|
-
(0,
|
|
565
|
-
(0,
|
|
803
|
+
AuthConfigModule = _ts_decorate5([
|
|
804
|
+
(0, import_common5.Global)(),
|
|
805
|
+
(0, import_common5.Module)({})
|
|
566
806
|
], AuthConfigModule);
|
|
567
807
|
|
|
568
808
|
// src/auth/decorators/onboarding.decorator.ts
|
|
569
|
-
var
|
|
570
|
-
var Onboarding = /* @__PURE__ */ __name(() => (0,
|
|
809
|
+
var import_common6 = require("@nestjs/common");
|
|
810
|
+
var Onboarding = /* @__PURE__ */ __name(() => (0, import_common6.SetMetadata)("isOnboarding", true), "Onboarding");
|
|
571
811
|
|
|
572
812
|
// src/auth/decorators/public.decorator.ts
|
|
573
|
-
var
|
|
574
|
-
var Public = /* @__PURE__ */ __name(() => (0,
|
|
813
|
+
var import_common7 = require("@nestjs/common");
|
|
814
|
+
var Public = /* @__PURE__ */ __name(() => (0, import_common7.SetMetadata)("isPublic", true), "Public");
|
|
575
815
|
|
|
576
816
|
// src/database/database.module.ts
|
|
577
817
|
var import_common12 = require("@nestjs/common");
|
|
578
|
-
var
|
|
579
|
-
|
|
580
|
-
// src/database/constants.ts
|
|
581
|
-
var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
|
|
818
|
+
var import_core5 = require("@nestjs/core");
|
|
582
819
|
|
|
583
820
|
// src/database/interceptors/message-tenant-context.interceptor.ts
|
|
584
|
-
var
|
|
821
|
+
var import_common9 = require("@nestjs/common");
|
|
585
822
|
var import_operators = require("rxjs/operators");
|
|
586
|
-
|
|
823
|
+
|
|
824
|
+
// src/database/services/tenant-context.service.ts
|
|
825
|
+
var import_common8 = require("@nestjs/common");
|
|
826
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
587
827
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
588
828
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
589
829
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
590
830
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
591
831
|
}
|
|
592
|
-
__name(
|
|
593
|
-
|
|
832
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
833
|
+
var TenantContextService = class {
|
|
834
|
+
static {
|
|
835
|
+
__name(this, "TenantContextService");
|
|
836
|
+
}
|
|
837
|
+
tenantInfo = null;
|
|
838
|
+
/**
|
|
839
|
+
* Set tenant information for this request/message
|
|
840
|
+
*
|
|
841
|
+
* This is typically called by:
|
|
842
|
+
* - TenantContextInterceptor (for HTTP requests in gateway)
|
|
843
|
+
* - MessageTenantContextInterceptor (for RabbitMQ messages in microservices)
|
|
844
|
+
* - Manual context setup in message handlers
|
|
845
|
+
*
|
|
846
|
+
* @param tenantInfo Complete tenant information
|
|
847
|
+
* @throws Error if tenant context is already set (prevents accidental overwrites)
|
|
848
|
+
*/
|
|
849
|
+
setTenant(tenantInfo) {
|
|
850
|
+
if (this.tenantInfo) {
|
|
851
|
+
throw new Error("Tenant context already set for this request");
|
|
852
|
+
}
|
|
853
|
+
this.tenantInfo = tenantInfo;
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Get tenant information for this request/message
|
|
857
|
+
*
|
|
858
|
+
* @returns Tenant information
|
|
859
|
+
* @throws UnauthorizedException if tenant context hasn't been set
|
|
860
|
+
*/
|
|
861
|
+
getTenant() {
|
|
862
|
+
if (!this.tenantInfo) {
|
|
863
|
+
throw new import_common8.UnauthorizedException("Tenant context not set");
|
|
864
|
+
}
|
|
865
|
+
return this.tenantInfo;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Check if tenant context has been set
|
|
869
|
+
*
|
|
870
|
+
* @returns true if tenant context is available
|
|
871
|
+
*/
|
|
872
|
+
hasTenant() {
|
|
873
|
+
return this.tenantInfo !== null;
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Clear tenant context
|
|
877
|
+
*
|
|
878
|
+
* This is useful for cleanup in RabbitMQ message handlers
|
|
879
|
+
* after the message has been processed.
|
|
880
|
+
*
|
|
881
|
+
* HTTP requests don't need manual cleanup as the service
|
|
882
|
+
* instance is destroyed when the request ends.
|
|
883
|
+
*/
|
|
884
|
+
clearTenant() {
|
|
885
|
+
this.tenantInfo = null;
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Get tenant ID safely (returns null if not set)
|
|
889
|
+
*
|
|
890
|
+
* @returns Tenant ID or null
|
|
891
|
+
*/
|
|
892
|
+
getTenantIdSafe() {
|
|
893
|
+
return this.tenantInfo?.id ?? null;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Get tenant subdomain safely (returns null if not set)
|
|
897
|
+
*
|
|
898
|
+
* @returns Tenant subdomain or null
|
|
899
|
+
*/
|
|
900
|
+
getTenantSubdomainSafe() {
|
|
901
|
+
return this.tenantInfo?.subdomain ?? null;
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
TenantContextService = _ts_decorate6([
|
|
905
|
+
(0, import_common8.Injectable)({
|
|
906
|
+
scope: import_common8.Scope.REQUEST
|
|
907
|
+
})
|
|
908
|
+
], TenantContextService);
|
|
909
|
+
|
|
910
|
+
// src/database/interceptors/message-tenant-context.interceptor.ts
|
|
911
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
912
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
913
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
914
|
+
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;
|
|
915
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
916
|
+
}
|
|
917
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
918
|
+
function _ts_metadata4(k, v) {
|
|
594
919
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
595
920
|
}
|
|
596
|
-
__name(
|
|
921
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
597
922
|
var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
|
|
598
923
|
static {
|
|
599
924
|
__name(this, "MessageTenantContextInterceptor");
|
|
600
925
|
}
|
|
601
926
|
tenantContext;
|
|
602
|
-
logger = new
|
|
927
|
+
logger = new import_common9.Logger(_MessageTenantContextInterceptor.name);
|
|
603
928
|
constructor(tenantContext) {
|
|
604
929
|
this.tenantContext = tenantContext;
|
|
605
930
|
}
|
|
@@ -644,29 +969,30 @@ var MessageTenantContextInterceptor = class _MessageTenantContextInterceptor {
|
|
|
644
969
|
}
|
|
645
970
|
}
|
|
646
971
|
};
|
|
647
|
-
MessageTenantContextInterceptor =
|
|
648
|
-
(0,
|
|
649
|
-
scope:
|
|
972
|
+
MessageTenantContextInterceptor = _ts_decorate7([
|
|
973
|
+
(0, import_common9.Injectable)({
|
|
974
|
+
scope: import_common9.Scope.REQUEST
|
|
650
975
|
}),
|
|
651
|
-
|
|
652
|
-
|
|
976
|
+
_ts_metadata4("design:type", Function),
|
|
977
|
+
_ts_metadata4("design:paramtypes", [
|
|
653
978
|
typeof TenantContextService === "undefined" ? Object : TenantContextService
|
|
654
979
|
])
|
|
655
980
|
], MessageTenantContextInterceptor);
|
|
656
981
|
|
|
657
982
|
// src/database/interceptors/tenant-context.interceptor.ts
|
|
658
|
-
var
|
|
659
|
-
|
|
983
|
+
var import_common10 = require("@nestjs/common");
|
|
984
|
+
var import_core4 = require("@nestjs/core");
|
|
985
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
660
986
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
661
987
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
662
988
|
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;
|
|
663
989
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
664
990
|
}
|
|
665
|
-
__name(
|
|
666
|
-
function
|
|
991
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
992
|
+
function _ts_metadata5(k, v) {
|
|
667
993
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
668
994
|
}
|
|
669
|
-
__name(
|
|
995
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
670
996
|
var TenantContextInterceptor = class _TenantContextInterceptor {
|
|
671
997
|
static {
|
|
672
998
|
__name(this, "TenantContextInterceptor");
|
|
@@ -675,7 +1001,7 @@ var TenantContextInterceptor = class _TenantContextInterceptor {
|
|
|
675
1001
|
tenantContext;
|
|
676
1002
|
primaryDatabase;
|
|
677
1003
|
requestService;
|
|
678
|
-
logger = new
|
|
1004
|
+
logger = new import_common10.Logger(_TenantContextInterceptor.name);
|
|
679
1005
|
constructor(reflector, tenantContext, primaryDatabase, requestService) {
|
|
680
1006
|
this.reflector = reflector;
|
|
681
1007
|
this.tenantContext = tenantContext;
|
|
@@ -696,7 +1022,7 @@ var TenantContextInterceptor = class _TenantContextInterceptor {
|
|
|
696
1022
|
return next.handle();
|
|
697
1023
|
}
|
|
698
1024
|
if (!tenantIdentifier) {
|
|
699
|
-
throw new
|
|
1025
|
+
throw new import_common10.UnauthorizedException("Tenant identifier not found in request");
|
|
700
1026
|
}
|
|
701
1027
|
this.logger.debug(`Tenant identifier extracted: ${tenantIdentifier}`);
|
|
702
1028
|
if (tenantIdentifier === "cloud") {
|
|
@@ -706,353 +1032,35 @@ var TenantContextInterceptor = class _TenantContextInterceptor {
|
|
|
706
1032
|
const tenantInfo = await this.primaryDatabase.getTenantInfo(tenantIdentifier);
|
|
707
1033
|
if (!tenantInfo) {
|
|
708
1034
|
this.logger.warn(`Invalid tenant: ${tenantIdentifier}`);
|
|
709
|
-
throw new
|
|
1035
|
+
throw new import_common10.UnauthorizedException("Invalid tenant");
|
|
710
1036
|
}
|
|
711
1037
|
if (tenantInfo.status !== "ACTIVE") {
|
|
712
|
-
this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
|
|
713
|
-
throw new
|
|
714
|
-
}
|
|
715
|
-
this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
|
|
716
|
-
this.tenantContext.setTenant(tenantInfo);
|
|
717
|
-
request.tenant = tenantInfo;
|
|
718
|
-
this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
|
|
719
|
-
} catch (error) {
|
|
720
|
-
this.logger.error("Failed to set tenant context", error);
|
|
721
|
-
throw error;
|
|
722
|
-
}
|
|
723
|
-
return next.handle();
|
|
724
|
-
}
|
|
725
|
-
};
|
|
726
|
-
TenantContextInterceptor = _ts_decorate6([
|
|
727
|
-
(0, import_common8.Injectable)({
|
|
728
|
-
scope: import_common8.Scope.REQUEST
|
|
729
|
-
}),
|
|
730
|
-
_ts_metadata4("design:type", Function),
|
|
731
|
-
_ts_metadata4("design:paramtypes", [
|
|
732
|
-
typeof Reflector === "undefined" ? Object : Reflector,
|
|
733
|
-
typeof TenantContextService === "undefined" ? Object : TenantContextService,
|
|
734
|
-
typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
|
|
735
|
-
typeof RequestService === "undefined" ? Object : RequestService
|
|
736
|
-
])
|
|
737
|
-
], TenantContextInterceptor);
|
|
738
|
-
|
|
739
|
-
// src/database/services/primary-database.service.ts
|
|
740
|
-
var import_common9 = require("@nestjs/common");
|
|
741
|
-
var import_drizzle_orm = require("drizzle-orm");
|
|
742
|
-
var import_node_postgres = require("drizzle-orm/node-postgres");
|
|
743
|
-
var import_pg = require("pg");
|
|
744
|
-
function _ts_decorate7(decorators, target, key, desc) {
|
|
745
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
746
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
747
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
748
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
749
|
-
}
|
|
750
|
-
__name(_ts_decorate7, "_ts_decorate");
|
|
751
|
-
function _ts_metadata5(k, v) {
|
|
752
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
753
|
-
}
|
|
754
|
-
__name(_ts_metadata5, "_ts_metadata");
|
|
755
|
-
function _ts_param2(paramIndex, decorator) {
|
|
756
|
-
return function(target, key) {
|
|
757
|
-
decorator(target, key, paramIndex);
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
__name(_ts_param2, "_ts_param");
|
|
761
|
-
var PrimaryDatabaseService2 = class _PrimaryDatabaseService {
|
|
762
|
-
static {
|
|
763
|
-
__name(this, "PrimaryDatabaseService");
|
|
764
|
-
}
|
|
765
|
-
options;
|
|
766
|
-
logger = new import_common9.Logger(_PrimaryDatabaseService.name);
|
|
767
|
-
/** PostgreSQL connection pool */
|
|
768
|
-
pool = null;
|
|
769
|
-
/** Drizzle database instance */
|
|
770
|
-
db = null;
|
|
771
|
-
/** In-memory cache: Map<tenantIdentifier, TenantConfig> */
|
|
772
|
-
tenantConfigCache = /* @__PURE__ */ new Map();
|
|
773
|
-
/** Cache TTL in milliseconds */
|
|
774
|
-
cacheTTL;
|
|
775
|
-
constructor(options) {
|
|
776
|
-
this.options = options;
|
|
777
|
-
this.cacheTTL = options.connectionCacheTTL || 3e5;
|
|
778
|
-
}
|
|
779
|
-
async onModuleInit() {
|
|
780
|
-
if (this.options.primaryDb) {
|
|
781
|
-
await this.initializeDrizzleClient();
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
/**
|
|
785
|
-
* Initialize connection to primary database using Drizzle
|
|
786
|
-
*/
|
|
787
|
-
async initializeDrizzleClient() {
|
|
788
|
-
try {
|
|
789
|
-
const databaseUrl = this.buildPrimaryDbUrl();
|
|
790
|
-
this.pool = new import_pg.Pool({
|
|
791
|
-
connectionString: databaseUrl,
|
|
792
|
-
max: this.options.maxConnections || 10
|
|
793
|
-
});
|
|
794
|
-
this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
|
|
795
|
-
this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
|
|
796
|
-
this.db = (0, import_node_postgres.drizzle)({
|
|
797
|
-
client: this.pool,
|
|
798
|
-
schema: this.options.drizzleSchema,
|
|
799
|
-
relations: this.options.drizzleRelations
|
|
800
|
-
});
|
|
801
|
-
this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
|
|
802
|
-
await this.pool.query("SELECT 1");
|
|
803
|
-
this.logger.log("Connected to primary database (tenant registry)");
|
|
804
|
-
} catch (error) {
|
|
805
|
-
this.logger.error("Failed to connect to primary database", error);
|
|
806
|
-
throw new import_common9.InternalServerErrorException("Failed to initialize tenant registry");
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* Build connection URL from primary database properties
|
|
811
|
-
*/
|
|
812
|
-
buildPrimaryDbUrl() {
|
|
813
|
-
if (!this.options.primaryDb) {
|
|
814
|
-
throw new Error("Primary database configuration not provided");
|
|
815
|
-
}
|
|
816
|
-
const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
|
|
817
|
-
let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
|
|
818
|
-
const params = new URLSearchParams();
|
|
819
|
-
if (schema) {
|
|
820
|
-
params.set("schema", schema);
|
|
821
|
-
}
|
|
822
|
-
params.set("sslmode", sslMode);
|
|
823
|
-
const queryString = params.toString();
|
|
824
|
-
if (queryString) {
|
|
825
|
-
url += `?${queryString}`;
|
|
826
|
-
}
|
|
827
|
-
this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
|
|
828
|
-
return url;
|
|
829
|
-
}
|
|
830
|
-
/**
|
|
831
|
-
* Mask password in connection URL for logging
|
|
832
|
-
*/
|
|
833
|
-
maskPassword(url) {
|
|
834
|
-
return url.replace(/:([^@]+)@/, ":****@");
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* Get tenant configuration by identifier (ID or subdomain)
|
|
838
|
-
*
|
|
839
|
-
* @param tenantIdentifier Tenant ID or subdomain
|
|
840
|
-
* @returns Tenant configuration or null if not found
|
|
841
|
-
*/
|
|
842
|
-
async getTenantInfo(tenantIdentifier) {
|
|
843
|
-
const cached = this.tenantConfigCache.get(tenantIdentifier);
|
|
844
|
-
if (cached) {
|
|
845
|
-
this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
|
|
846
|
-
return cached;
|
|
847
|
-
}
|
|
848
|
-
try {
|
|
849
|
-
if (!this.db) {
|
|
850
|
-
throw new Error("Primary database client not initialized");
|
|
851
|
-
}
|
|
852
|
-
this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
|
|
853
|
-
const schema = this.options.drizzleSchema;
|
|
854
|
-
const { tenants, tenantDatabaseConfigs } = schema;
|
|
855
|
-
const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, (0, import_drizzle_orm.eq)(tenants.id, tenantDatabaseConfigs.tenantId)).where((0, import_drizzle_orm.or)((0, import_drizzle_orm.eq)(tenants.id, tenantIdentifier), (0, import_drizzle_orm.eq)(tenants.subdomain, tenantIdentifier))).limit(1);
|
|
856
|
-
if (!result.length) {
|
|
857
|
-
this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
|
|
858
|
-
return null;
|
|
859
|
-
}
|
|
860
|
-
const row = result[0];
|
|
861
|
-
const tenant = row.tenants;
|
|
862
|
-
const config = row.tenant_database_configs;
|
|
863
|
-
if (tenant.status !== "ACTIVE") {
|
|
864
|
-
this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
|
|
865
|
-
return null;
|
|
866
|
-
}
|
|
867
|
-
const info = {
|
|
868
|
-
id: tenant.id,
|
|
869
|
-
subdomain: tenant.subdomain,
|
|
870
|
-
type: tenant.dbType,
|
|
871
|
-
status: tenant.status,
|
|
872
|
-
// For SHARED tenants: schema name
|
|
873
|
-
schemaName: config?.dbSchema || void 0,
|
|
874
|
-
// For DEDICATED tenants: database configuration from TenantDatabaseConfig table
|
|
875
|
-
databaseName: config?.dbName || void 0,
|
|
876
|
-
databaseHost: config?.dbHost || void 0,
|
|
877
|
-
databasePort: config?.dbPort || void 0,
|
|
878
|
-
databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
|
|
879
|
-
databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
|
|
880
|
-
databaseSslMode: config?.dbSslMode || void 0,
|
|
881
|
-
connectionPoolSize: config?.connectionPoolSize || void 0
|
|
882
|
-
};
|
|
883
|
-
this.cacheInfo(info);
|
|
884
|
-
return info;
|
|
885
|
-
} catch (error) {
|
|
886
|
-
this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
|
|
887
|
-
throw new import_common9.InternalServerErrorException("Failed to resolve tenant");
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* Cache tenant information with TTL
|
|
892
|
-
*/
|
|
893
|
-
cacheInfo(info) {
|
|
894
|
-
this.tenantConfigCache.set(info.id, info);
|
|
895
|
-
this.tenantConfigCache.set(info.subdomain, info);
|
|
896
|
-
setTimeout(() => {
|
|
897
|
-
this.tenantConfigCache.delete(info.id);
|
|
898
|
-
this.tenantConfigCache.delete(info.subdomain);
|
|
899
|
-
this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
|
|
900
|
-
}, this.cacheTTL);
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* Clear cached tenant information
|
|
904
|
-
*
|
|
905
|
-
* Useful when tenant settings are updated and cache needs to be invalidated
|
|
906
|
-
*
|
|
907
|
-
* @param tenantIdentifier Tenant ID or subdomain
|
|
908
|
-
*/
|
|
909
|
-
clearTenantCache(tenantIdentifier) {
|
|
910
|
-
const config = this.tenantConfigCache.get(tenantIdentifier);
|
|
911
|
-
if (config) {
|
|
912
|
-
this.tenantConfigCache.delete(config.id);
|
|
913
|
-
this.tenantConfigCache.delete(config.subdomain);
|
|
914
|
-
this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
/**
|
|
918
|
-
* Clear all cached tenant configurations
|
|
919
|
-
*/
|
|
920
|
-
clearAllCaches() {
|
|
921
|
-
const size = this.tenantConfigCache.size;
|
|
922
|
-
this.tenantConfigCache.clear();
|
|
923
|
-
this.logger.log(`Cleared ${size} cached tenant configs`);
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Get the Drizzle database instance for the primary database.
|
|
927
|
-
* This is a synchronous property that returns the initialized Drizzle client.
|
|
928
|
-
*
|
|
929
|
-
* @returns Primary database Drizzle instance
|
|
930
|
-
* @throws Error if primary database client is not initialized
|
|
931
|
-
*/
|
|
932
|
-
get drizzleClient() {
|
|
933
|
-
if (!this.db) {
|
|
934
|
-
throw new Error("Primary database client not initialized");
|
|
935
|
-
}
|
|
936
|
-
return this.db;
|
|
937
|
-
}
|
|
938
|
-
/**
|
|
939
|
-
* Get the Drizzle schema
|
|
940
|
-
*/
|
|
941
|
-
get schema() {
|
|
942
|
-
return this.options.drizzleSchema;
|
|
943
|
-
}
|
|
944
|
-
/**
|
|
945
|
-
* Decrypt database credentials
|
|
946
|
-
*
|
|
947
|
-
* Override this method to implement your encryption strategy
|
|
948
|
-
*
|
|
949
|
-
* @param encrypted Encrypted value
|
|
950
|
-
* @returns Decrypted value
|
|
951
|
-
*/
|
|
952
|
-
decrypt(encrypted) {
|
|
953
|
-
return encrypted;
|
|
954
|
-
}
|
|
955
|
-
async onModuleDestroy() {
|
|
956
|
-
if (this.pool) {
|
|
957
|
-
await this.pool.end();
|
|
958
|
-
this.logger.log("Disconnected from primary database");
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
};
|
|
962
|
-
PrimaryDatabaseService2 = _ts_decorate7([
|
|
963
|
-
(0, import_common9.Injectable)(),
|
|
964
|
-
_ts_param2(0, (0, import_common9.Inject)(DATABASE_MODULE_OPTIONS)),
|
|
965
|
-
_ts_metadata5("design:type", Function),
|
|
966
|
-
_ts_metadata5("design:paramtypes", [
|
|
967
|
-
typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
|
|
968
|
-
])
|
|
969
|
-
], PrimaryDatabaseService2);
|
|
970
|
-
|
|
971
|
-
// src/database/services/tenant-context.service.ts
|
|
972
|
-
var import_common10 = require("@nestjs/common");
|
|
973
|
-
function _ts_decorate8(decorators, target, key, desc) {
|
|
974
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
975
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
976
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
977
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
978
|
-
}
|
|
979
|
-
__name(_ts_decorate8, "_ts_decorate");
|
|
980
|
-
var TenantContextService2 = class {
|
|
981
|
-
static {
|
|
982
|
-
__name(this, "TenantContextService");
|
|
983
|
-
}
|
|
984
|
-
tenantInfo = null;
|
|
985
|
-
/**
|
|
986
|
-
* Set tenant information for this request/message
|
|
987
|
-
*
|
|
988
|
-
* This is typically called by:
|
|
989
|
-
* - TenantContextInterceptor (for HTTP requests in gateway)
|
|
990
|
-
* - MessageTenantContextInterceptor (for RabbitMQ messages in microservices)
|
|
991
|
-
* - Manual context setup in message handlers
|
|
992
|
-
*
|
|
993
|
-
* @param tenantInfo Complete tenant information
|
|
994
|
-
* @throws Error if tenant context is already set (prevents accidental overwrites)
|
|
995
|
-
*/
|
|
996
|
-
setTenant(tenantInfo) {
|
|
997
|
-
if (this.tenantInfo) {
|
|
998
|
-
throw new Error("Tenant context already set for this request");
|
|
999
|
-
}
|
|
1000
|
-
this.tenantInfo = tenantInfo;
|
|
1001
|
-
}
|
|
1002
|
-
/**
|
|
1003
|
-
* Get tenant information for this request/message
|
|
1004
|
-
*
|
|
1005
|
-
* @returns Tenant information
|
|
1006
|
-
* @throws UnauthorizedException if tenant context hasn't been set
|
|
1007
|
-
*/
|
|
1008
|
-
getTenant() {
|
|
1009
|
-
if (!this.tenantInfo) {
|
|
1010
|
-
throw new import_common10.UnauthorizedException("Tenant context not set");
|
|
1011
|
-
}
|
|
1012
|
-
return this.tenantInfo;
|
|
1013
|
-
}
|
|
1014
|
-
/**
|
|
1015
|
-
* Check if tenant context has been set
|
|
1016
|
-
*
|
|
1017
|
-
* @returns true if tenant context is available
|
|
1018
|
-
*/
|
|
1019
|
-
hasTenant() {
|
|
1020
|
-
return this.tenantInfo !== null;
|
|
1021
|
-
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Clear tenant context
|
|
1024
|
-
*
|
|
1025
|
-
* This is useful for cleanup in RabbitMQ message handlers
|
|
1026
|
-
* after the message has been processed.
|
|
1027
|
-
*
|
|
1028
|
-
* HTTP requests don't need manual cleanup as the service
|
|
1029
|
-
* instance is destroyed when the request ends.
|
|
1030
|
-
*/
|
|
1031
|
-
clearTenant() {
|
|
1032
|
-
this.tenantInfo = null;
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* Get tenant ID safely (returns null if not set)
|
|
1036
|
-
*
|
|
1037
|
-
* @returns Tenant ID or null
|
|
1038
|
-
*/
|
|
1039
|
-
getTenantIdSafe() {
|
|
1040
|
-
return this.tenantInfo?.id ?? null;
|
|
1041
|
-
}
|
|
1042
|
-
/**
|
|
1043
|
-
* Get tenant subdomain safely (returns null if not set)
|
|
1044
|
-
*
|
|
1045
|
-
* @returns Tenant subdomain or null
|
|
1046
|
-
*/
|
|
1047
|
-
getTenantSubdomainSafe() {
|
|
1048
|
-
return this.tenantInfo?.subdomain ?? null;
|
|
1038
|
+
this.logger.warn(`Tenant ${tenantIdentifier} has status: ${tenantInfo.status}`);
|
|
1039
|
+
throw new import_common10.UnauthorizedException(`Tenant is ${tenantInfo.status}`);
|
|
1040
|
+
}
|
|
1041
|
+
this.logger.debug(`Tenant config loaded: ${tenantInfo.subdomain} (${tenantInfo.type})`);
|
|
1042
|
+
this.tenantContext.setTenant(tenantInfo);
|
|
1043
|
+
request.tenant = tenantInfo;
|
|
1044
|
+
this.logger.log(`Tenant context set: ${tenantInfo.subdomain}`);
|
|
1045
|
+
} catch (error) {
|
|
1046
|
+
this.logger.error("Failed to set tenant context", error);
|
|
1047
|
+
throw error;
|
|
1048
|
+
}
|
|
1049
|
+
return next.handle();
|
|
1049
1050
|
}
|
|
1050
1051
|
};
|
|
1051
|
-
|
|
1052
|
+
TenantContextInterceptor = _ts_decorate8([
|
|
1052
1053
|
(0, import_common10.Injectable)({
|
|
1053
1054
|
scope: import_common10.Scope.REQUEST
|
|
1054
|
-
})
|
|
1055
|
-
|
|
1055
|
+
}),
|
|
1056
|
+
_ts_metadata5("design:type", Function),
|
|
1057
|
+
_ts_metadata5("design:paramtypes", [
|
|
1058
|
+
typeof import_core4.Reflector === "undefined" ? Object : import_core4.Reflector,
|
|
1059
|
+
typeof TenantContextService === "undefined" ? Object : TenantContextService,
|
|
1060
|
+
typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
|
|
1061
|
+
typeof RequestService === "undefined" ? Object : RequestService
|
|
1062
|
+
])
|
|
1063
|
+
], TenantContextInterceptor);
|
|
1056
1064
|
|
|
1057
1065
|
// src/database/services/tenant-database.service.ts
|
|
1058
1066
|
var import_common11 = require("@nestjs/common");
|
|
@@ -1339,18 +1347,18 @@ var DatabaseModule = class _DatabaseModule {
|
|
|
1339
1347
|
};
|
|
1340
1348
|
const providers = [
|
|
1341
1349
|
asyncProvider,
|
|
1342
|
-
|
|
1343
|
-
|
|
1350
|
+
TenantContextService,
|
|
1351
|
+
PrimaryDatabaseService,
|
|
1344
1352
|
TenantDatabaseService
|
|
1345
1353
|
];
|
|
1346
1354
|
if (mode === "server") {
|
|
1347
1355
|
providers.push({
|
|
1348
|
-
provide:
|
|
1356
|
+
provide: import_core5.APP_INTERCEPTOR,
|
|
1349
1357
|
useClass: TenantContextInterceptor
|
|
1350
1358
|
});
|
|
1351
1359
|
} else {
|
|
1352
1360
|
providers.push({
|
|
1353
|
-
provide:
|
|
1361
|
+
provide: import_core5.APP_INTERCEPTOR,
|
|
1354
1362
|
useClass: MessageTenantContextInterceptor
|
|
1355
1363
|
});
|
|
1356
1364
|
}
|
|
@@ -1362,8 +1370,8 @@ var DatabaseModule = class _DatabaseModule {
|
|
|
1362
1370
|
providers,
|
|
1363
1371
|
exports: [
|
|
1364
1372
|
TenantDatabaseService,
|
|
1365
|
-
|
|
1366
|
-
|
|
1373
|
+
TenantContextService,
|
|
1374
|
+
PrimaryDatabaseService,
|
|
1367
1375
|
asyncProvider
|
|
1368
1376
|
]
|
|
1369
1377
|
};
|
|
@@ -1378,7 +1386,7 @@ DatabaseModule = _ts_decorate10([
|
|
|
1378
1386
|
var import_common13 = require("@nestjs/common");
|
|
1379
1387
|
var Tenant = (0, import_common13.createParamDecorator)((_data, ctx) => {
|
|
1380
1388
|
const request = ctx.switchToHttp().getRequest();
|
|
1381
|
-
const tenantContext = request.app?.get?.(
|
|
1389
|
+
const tenantContext = request.app?.get?.(TenantContextService);
|
|
1382
1390
|
if (!tenantContext) {
|
|
1383
1391
|
throw new Error("TenantContextService not found.");
|
|
1384
1392
|
}
|
|
@@ -2540,267 +2548,74 @@ HttpModule = _ts_decorate13([
|
|
|
2540
2548
|
(0, import_common37.Module)({
|
|
2541
2549
|
providers: [
|
|
2542
2550
|
CsrfGuard
|
|
2543
|
-
],
|
|
2544
|
-
exports: [
|
|
2545
|
-
CsrfGuard
|
|
2546
|
-
]
|
|
2547
|
-
})
|
|
2548
|
-
], HttpModule);
|
|
2549
|
-
|
|
2550
|
-
// src/logger/interceptors/http-logger.interceptor.ts
|
|
2551
|
-
var
|
|
2552
|
-
var import_operators2 = require("rxjs/operators");
|
|
2553
|
-
|
|
2554
|
-
// src/logger/utils/index.ts
|
|
2555
|
-
var import_node_async_hooks = require("async_hooks");
|
|
2556
|
-
var import_node_crypto = require("crypto");
|
|
2557
|
-
var correlationStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
2558
|
-
function getCorrelationContext() {
|
|
2559
|
-
return correlationStorage.getStore();
|
|
2560
|
-
}
|
|
2561
|
-
__name(getCorrelationContext, "getCorrelationContext");
|
|
2562
|
-
function runWithCorrelationContext(context, callback) {
|
|
2563
|
-
return correlationStorage.run(context, callback);
|
|
2564
|
-
}
|
|
2565
|
-
__name(runWithCorrelationContext, "runWithCorrelationContext");
|
|
2566
|
-
function updateCorrelationContext(updates) {
|
|
2567
|
-
const context = correlationStorage.getStore();
|
|
2568
|
-
if (context) {
|
|
2569
|
-
Object.assign(context, updates);
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
__name(updateCorrelationContext, "updateCorrelationContext");
|
|
2573
|
-
var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
|
|
2574
|
-
function generateCorrelationId() {
|
|
2575
|
-
return (0, import_node_crypto.randomUUID)();
|
|
2576
|
-
}
|
|
2577
|
-
__name(generateCorrelationId, "generateCorrelationId");
|
|
2578
|
-
function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
|
|
2579
|
-
if (typeof reply.header === "function") {
|
|
2580
|
-
reply.header(headerName, correlationId);
|
|
2581
|
-
} else if (reply.raw && typeof reply.raw.setHeader === "function") {
|
|
2582
|
-
reply.raw.setHeader(headerName, correlationId);
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
__name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
|
|
2586
|
-
|
|
2587
|
-
// src/logger/interceptors/http-logger.interceptor.ts
|
|
2588
|
-
function _ts_decorate14(decorators, target, key, desc) {
|
|
2589
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2590
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2591
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2592
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2593
|
-
}
|
|
2594
|
-
__name(_ts_decorate14, "_ts_decorate");
|
|
2595
|
-
function _ts_metadata7(k, v) {
|
|
2596
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2597
|
-
}
|
|
2598
|
-
__name(_ts_metadata7, "_ts_metadata");
|
|
2599
|
-
function _ts_param4(paramIndex, decorator) {
|
|
2600
|
-
return function(target, key) {
|
|
2601
|
-
decorator(target, key, paramIndex);
|
|
2602
|
-
};
|
|
2603
|
-
}
|
|
2604
|
-
__name(_ts_param4, "_ts_param");
|
|
2605
|
-
var HttpLoggerInterceptor = class {
|
|
2606
|
-
static {
|
|
2607
|
-
__name(this, "HttpLoggerInterceptor");
|
|
2608
|
-
}
|
|
2609
|
-
logger;
|
|
2610
|
-
enableRequestLog;
|
|
2611
|
-
enableResponseLog;
|
|
2612
|
-
slowRequestThreshold;
|
|
2613
|
-
constructor(logger, options) {
|
|
2614
|
-
this.logger = logger;
|
|
2615
|
-
this.enableRequestLog = options?.enableRequestLog ?? true;
|
|
2616
|
-
this.enableResponseLog = options?.enableResponseLog ?? true;
|
|
2617
|
-
this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
|
|
2618
|
-
}
|
|
2619
|
-
intercept(context, next) {
|
|
2620
|
-
if (context.getType() !== "http") {
|
|
2621
|
-
return next.handle();
|
|
2622
|
-
}
|
|
2623
|
-
const httpContext = context.switchToHttp();
|
|
2624
|
-
const request = httpContext.getRequest();
|
|
2625
|
-
const response = httpContext.getResponse();
|
|
2626
|
-
const startTime = Date.now();
|
|
2627
|
-
if (this.enableRequestLog) {
|
|
2628
|
-
this.logRequest(request);
|
|
2629
|
-
}
|
|
2630
|
-
return next.handle().pipe((0, import_operators2.tap)(() => {
|
|
2631
|
-
if (this.enableResponseLog) {
|
|
2632
|
-
const duration = Date.now() - startTime;
|
|
2633
|
-
this.logResponse(request, response, duration);
|
|
2634
|
-
}
|
|
2635
|
-
}), (0, import_operators2.catchError)((error) => {
|
|
2636
|
-
const duration = Date.now() - startTime;
|
|
2637
|
-
this.logError(request, response, duration, error);
|
|
2638
|
-
throw error;
|
|
2639
|
-
}));
|
|
2640
|
-
}
|
|
2641
|
-
logRequest(request) {
|
|
2642
|
-
try {
|
|
2643
|
-
const correlationContext = getCorrelationContext();
|
|
2644
|
-
const metadata = {
|
|
2645
|
-
type: "http_request",
|
|
2646
|
-
method: request.method,
|
|
2647
|
-
url: request.url,
|
|
2648
|
-
correlationId: correlationContext?.correlationId,
|
|
2649
|
-
ip: request.ip,
|
|
2650
|
-
userAgent: request.headers["user-agent"]
|
|
2651
|
-
};
|
|
2652
|
-
this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
|
|
2653
|
-
} catch (error) {
|
|
2654
|
-
this.logger.error("Failed to log HTTP request", error.stack);
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
logResponse(request, response, duration) {
|
|
2658
|
-
try {
|
|
2659
|
-
const correlationContext = getCorrelationContext();
|
|
2660
|
-
const statusCode = response.statusCode;
|
|
2661
|
-
const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
|
|
2662
|
-
const metadata = {
|
|
2663
|
-
type: "http_response",
|
|
2664
|
-
method: request.method,
|
|
2665
|
-
url: request.url,
|
|
2666
|
-
statusCode,
|
|
2667
|
-
duration,
|
|
2668
|
-
correlationId: correlationContext?.correlationId
|
|
2669
|
-
};
|
|
2670
|
-
if (duration > this.slowRequestThreshold) {
|
|
2671
|
-
metadata.slowRequest = true;
|
|
2672
|
-
}
|
|
2673
|
-
const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
|
|
2674
|
-
this.logger.logWithMetadata(logLevel, message, metadata);
|
|
2675
|
-
} catch (error) {
|
|
2676
|
-
this.logger.error("Failed to log HTTP response", error.stack);
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
logError(request, response, duration, error) {
|
|
2680
|
-
try {
|
|
2681
|
-
const correlationContext = getCorrelationContext();
|
|
2682
|
-
const statusCode = response.statusCode || 500;
|
|
2683
|
-
const metadata = {
|
|
2684
|
-
type: "http_error",
|
|
2685
|
-
method: request.method,
|
|
2686
|
-
url: request.url,
|
|
2687
|
-
statusCode,
|
|
2688
|
-
duration,
|
|
2689
|
-
correlationId: correlationContext?.correlationId,
|
|
2690
|
-
errorName: error?.name || "Error",
|
|
2691
|
-
errorMessage: error?.message || "Unknown error"
|
|
2692
|
-
};
|
|
2693
|
-
if (error?.stack) {
|
|
2694
|
-
metadata.trace = error.stack;
|
|
2695
|
-
}
|
|
2696
|
-
if (error?.response) {
|
|
2697
|
-
metadata.errorDetails = error.response;
|
|
2698
|
-
}
|
|
2699
|
-
const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
|
|
2700
|
-
this.logger.logWithMetadata("error", message, metadata);
|
|
2701
|
-
} catch (loggingError) {
|
|
2702
|
-
this.logger.error("Failed to log HTTP error", loggingError.stack);
|
|
2703
|
-
}
|
|
2704
|
-
}
|
|
2705
|
-
};
|
|
2706
|
-
HttpLoggerInterceptor = _ts_decorate14([
|
|
2707
|
-
(0, import_common38.Injectable)(),
|
|
2708
|
-
_ts_param4(1, (0, import_common38.Optional)()),
|
|
2709
|
-
_ts_metadata7("design:type", Function),
|
|
2710
|
-
_ts_metadata7("design:paramtypes", [
|
|
2711
|
-
typeof LoggerService === "undefined" ? Object : LoggerService,
|
|
2712
|
-
typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
|
|
2713
|
-
])
|
|
2714
|
-
], HttpLoggerInterceptor);
|
|
2715
|
-
|
|
2716
|
-
// src/logger/logger.module.ts
|
|
2717
|
-
var import_common41 = require("@nestjs/common");
|
|
2718
|
-
|
|
2719
|
-
// src/logger/middleware/correlation-id.middleware.ts
|
|
2720
|
-
var import_common39 = require("@nestjs/common");
|
|
2721
|
-
function _ts_decorate15(decorators, target, key, desc) {
|
|
2722
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2723
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2724
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2725
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2726
|
-
}
|
|
2727
|
-
__name(_ts_decorate15, "_ts_decorate");
|
|
2728
|
-
function _ts_metadata8(k, v) {
|
|
2729
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2730
|
-
}
|
|
2731
|
-
__name(_ts_metadata8, "_ts_metadata");
|
|
2732
|
-
var CorrelationIdMiddleware = class {
|
|
2733
|
-
static {
|
|
2734
|
-
__name(this, "CorrelationIdMiddleware");
|
|
2735
|
-
}
|
|
2736
|
-
includeInResponse;
|
|
2737
|
-
responseHeader;
|
|
2738
|
-
constructor(options = {}) {
|
|
2739
|
-
this.includeInResponse = options.includeInResponse ?? true;
|
|
2740
|
-
this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
|
|
2741
|
-
}
|
|
2742
|
-
/**
|
|
2743
|
-
* Middleware handler for processing requests.
|
|
2744
|
-
*/
|
|
2745
|
-
use(_req, reply, next) {
|
|
2746
|
-
const correlationId = generateCorrelationId();
|
|
2747
|
-
if (this.includeInResponse) {
|
|
2748
|
-
addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
|
|
2749
|
-
}
|
|
2750
|
-
runWithCorrelationContext({
|
|
2751
|
-
correlationId
|
|
2752
|
-
}, () => {
|
|
2753
|
-
next();
|
|
2754
|
-
});
|
|
2755
|
-
}
|
|
2756
|
-
/**
|
|
2757
|
-
* Fastify hook handler for onRequest.
|
|
2758
|
-
* This is an async function that returns a Promise, ensuring the AsyncLocalStorage
|
|
2759
|
-
* context persists throughout the entire request lifecycle.
|
|
2760
|
-
*/
|
|
2761
|
-
async onRequest(_req, reply) {
|
|
2762
|
-
const correlationId = generateCorrelationId();
|
|
2763
|
-
if (this.includeInResponse) {
|
|
2764
|
-
addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
|
|
2765
|
-
}
|
|
2766
|
-
const store = correlationStorage.getStore();
|
|
2767
|
-
if (!store) {
|
|
2768
|
-
correlationStorage.enterWith({
|
|
2769
|
-
correlationId
|
|
2770
|
-
});
|
|
2771
|
-
}
|
|
2772
|
-
}
|
|
2773
|
-
};
|
|
2774
|
-
CorrelationIdMiddleware = _ts_decorate15([
|
|
2775
|
-
(0, import_common39.Injectable)(),
|
|
2776
|
-
_ts_metadata8("design:type", Function),
|
|
2777
|
-
_ts_metadata8("design:paramtypes", [
|
|
2778
|
-
typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
|
|
2779
|
-
])
|
|
2780
|
-
], CorrelationIdMiddleware);
|
|
2551
|
+
],
|
|
2552
|
+
exports: [
|
|
2553
|
+
CsrfGuard
|
|
2554
|
+
]
|
|
2555
|
+
})
|
|
2556
|
+
], HttpModule);
|
|
2557
|
+
|
|
2558
|
+
// src/logger/interceptors/http-logger.interceptor.ts
|
|
2559
|
+
var import_common39 = require("@nestjs/common");
|
|
2560
|
+
var import_operators2 = require("rxjs/operators");
|
|
2781
2561
|
|
|
2782
2562
|
// src/logger/services/logger.service.ts
|
|
2783
|
-
var
|
|
2563
|
+
var import_common38 = require("@nestjs/common");
|
|
2784
2564
|
var import_winston = require("winston");
|
|
2785
2565
|
var import_winston_daily_rotate_file = __toESM(require("winston-daily-rotate-file"), 1);
|
|
2786
|
-
|
|
2566
|
+
|
|
2567
|
+
// src/logger/utils/index.ts
|
|
2568
|
+
var import_node_async_hooks = require("async_hooks");
|
|
2569
|
+
var import_node_crypto = require("crypto");
|
|
2570
|
+
var correlationStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
2571
|
+
function getCorrelationContext() {
|
|
2572
|
+
return correlationStorage.getStore();
|
|
2573
|
+
}
|
|
2574
|
+
__name(getCorrelationContext, "getCorrelationContext");
|
|
2575
|
+
function runWithCorrelationContext(context, callback) {
|
|
2576
|
+
return correlationStorage.run(context, callback);
|
|
2577
|
+
}
|
|
2578
|
+
__name(runWithCorrelationContext, "runWithCorrelationContext");
|
|
2579
|
+
function updateCorrelationContext(updates) {
|
|
2580
|
+
const context = correlationStorage.getStore();
|
|
2581
|
+
if (context) {
|
|
2582
|
+
Object.assign(context, updates);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
__name(updateCorrelationContext, "updateCorrelationContext");
|
|
2586
|
+
var DEFAULT_CORRELATION_HEADER = "x-correlation-id";
|
|
2587
|
+
function generateCorrelationId() {
|
|
2588
|
+
return (0, import_node_crypto.randomUUID)();
|
|
2589
|
+
}
|
|
2590
|
+
__name(generateCorrelationId, "generateCorrelationId");
|
|
2591
|
+
function addCorrelationIdToResponse(reply, correlationId, headerName = DEFAULT_CORRELATION_HEADER) {
|
|
2592
|
+
if (typeof reply.header === "function") {
|
|
2593
|
+
reply.header(headerName, correlationId);
|
|
2594
|
+
} else if (reply.raw && typeof reply.raw.setHeader === "function") {
|
|
2595
|
+
reply.raw.setHeader(headerName, correlationId);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
__name(addCorrelationIdToResponse, "addCorrelationIdToResponse");
|
|
2599
|
+
|
|
2600
|
+
// src/logger/services/logger.service.ts
|
|
2601
|
+
function _ts_decorate14(decorators, target, key, desc) {
|
|
2787
2602
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2788
2603
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2789
2604
|
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;
|
|
2790
2605
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2791
2606
|
}
|
|
2792
|
-
__name(
|
|
2793
|
-
function
|
|
2607
|
+
__name(_ts_decorate14, "_ts_decorate");
|
|
2608
|
+
function _ts_metadata7(k, v) {
|
|
2794
2609
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2795
2610
|
}
|
|
2796
|
-
__name(
|
|
2797
|
-
function
|
|
2611
|
+
__name(_ts_metadata7, "_ts_metadata");
|
|
2612
|
+
function _ts_param4(paramIndex, decorator) {
|
|
2798
2613
|
return function(target, key) {
|
|
2799
2614
|
decorator(target, key, paramIndex);
|
|
2800
2615
|
};
|
|
2801
2616
|
}
|
|
2802
|
-
__name(
|
|
2803
|
-
var
|
|
2617
|
+
__name(_ts_param4, "_ts_param");
|
|
2618
|
+
var LoggerService = class _LoggerService {
|
|
2804
2619
|
static {
|
|
2805
2620
|
__name(this, "LoggerService");
|
|
2806
2621
|
}
|
|
@@ -3001,16 +2816,211 @@ ${trace}`;
|
|
|
3001
2816
|
return childLogger;
|
|
3002
2817
|
}
|
|
3003
2818
|
};
|
|
3004
|
-
|
|
2819
|
+
LoggerService = _ts_decorate14([
|
|
2820
|
+
(0, import_common38.Injectable)(),
|
|
2821
|
+
_ts_param4(0, (0, import_common38.Optional)()),
|
|
2822
|
+
_ts_param4(1, (0, import_common38.Optional)()),
|
|
2823
|
+
_ts_metadata7("design:type", Function),
|
|
2824
|
+
_ts_metadata7("design:paramtypes", [
|
|
2825
|
+
typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
|
|
2826
|
+
typeof Logger === "undefined" ? Object : Logger
|
|
2827
|
+
])
|
|
2828
|
+
], LoggerService);
|
|
2829
|
+
|
|
2830
|
+
// src/logger/interceptors/http-logger.interceptor.ts
|
|
2831
|
+
function _ts_decorate15(decorators, target, key, desc) {
|
|
2832
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2833
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2834
|
+
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;
|
|
2835
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2836
|
+
}
|
|
2837
|
+
__name(_ts_decorate15, "_ts_decorate");
|
|
2838
|
+
function _ts_metadata8(k, v) {
|
|
2839
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2840
|
+
}
|
|
2841
|
+
__name(_ts_metadata8, "_ts_metadata");
|
|
2842
|
+
function _ts_param5(paramIndex, decorator) {
|
|
2843
|
+
return function(target, key) {
|
|
2844
|
+
decorator(target, key, paramIndex);
|
|
2845
|
+
};
|
|
2846
|
+
}
|
|
2847
|
+
__name(_ts_param5, "_ts_param");
|
|
2848
|
+
var HttpLoggerInterceptor = class {
|
|
2849
|
+
static {
|
|
2850
|
+
__name(this, "HttpLoggerInterceptor");
|
|
2851
|
+
}
|
|
2852
|
+
logger;
|
|
2853
|
+
enableRequestLog;
|
|
2854
|
+
enableResponseLog;
|
|
2855
|
+
slowRequestThreshold;
|
|
2856
|
+
constructor(logger, options) {
|
|
2857
|
+
this.logger = logger;
|
|
2858
|
+
this.enableRequestLog = options?.enableRequestLog ?? true;
|
|
2859
|
+
this.enableResponseLog = options?.enableResponseLog ?? true;
|
|
2860
|
+
this.slowRequestThreshold = options?.slowRequestThreshold ?? 3e3;
|
|
2861
|
+
}
|
|
2862
|
+
intercept(context, next) {
|
|
2863
|
+
if (context.getType() !== "http") {
|
|
2864
|
+
return next.handle();
|
|
2865
|
+
}
|
|
2866
|
+
const httpContext = context.switchToHttp();
|
|
2867
|
+
const request = httpContext.getRequest();
|
|
2868
|
+
const response = httpContext.getResponse();
|
|
2869
|
+
const startTime = Date.now();
|
|
2870
|
+
if (this.enableRequestLog) {
|
|
2871
|
+
this.logRequest(request);
|
|
2872
|
+
}
|
|
2873
|
+
return next.handle().pipe((0, import_operators2.tap)(() => {
|
|
2874
|
+
if (this.enableResponseLog) {
|
|
2875
|
+
const duration = Date.now() - startTime;
|
|
2876
|
+
this.logResponse(request, response, duration);
|
|
2877
|
+
}
|
|
2878
|
+
}), (0, import_operators2.catchError)((error) => {
|
|
2879
|
+
const duration = Date.now() - startTime;
|
|
2880
|
+
this.logError(request, response, duration, error);
|
|
2881
|
+
throw error;
|
|
2882
|
+
}));
|
|
2883
|
+
}
|
|
2884
|
+
logRequest(request) {
|
|
2885
|
+
try {
|
|
2886
|
+
const correlationContext = getCorrelationContext();
|
|
2887
|
+
const metadata = {
|
|
2888
|
+
type: "http_request",
|
|
2889
|
+
method: request.method,
|
|
2890
|
+
url: request.url,
|
|
2891
|
+
correlationId: correlationContext?.correlationId,
|
|
2892
|
+
ip: request.ip,
|
|
2893
|
+
userAgent: request.headers["user-agent"]
|
|
2894
|
+
};
|
|
2895
|
+
this.logger.logWithMetadata("log", `Incoming ${request.method} ${request.url}`, metadata);
|
|
2896
|
+
} catch (error) {
|
|
2897
|
+
this.logger.error("Failed to log HTTP request", error.stack);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
logResponse(request, response, duration) {
|
|
2901
|
+
try {
|
|
2902
|
+
const correlationContext = getCorrelationContext();
|
|
2903
|
+
const statusCode = response.statusCode;
|
|
2904
|
+
const logLevel = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "log";
|
|
2905
|
+
const metadata = {
|
|
2906
|
+
type: "http_response",
|
|
2907
|
+
method: request.method,
|
|
2908
|
+
url: request.url,
|
|
2909
|
+
statusCode,
|
|
2910
|
+
duration,
|
|
2911
|
+
correlationId: correlationContext?.correlationId
|
|
2912
|
+
};
|
|
2913
|
+
if (duration > this.slowRequestThreshold) {
|
|
2914
|
+
metadata.slowRequest = true;
|
|
2915
|
+
}
|
|
2916
|
+
const message = metadata.slowRequest ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms` : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;
|
|
2917
|
+
this.logger.logWithMetadata(logLevel, message, metadata);
|
|
2918
|
+
} catch (error) {
|
|
2919
|
+
this.logger.error("Failed to log HTTP response", error.stack);
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
logError(request, response, duration, error) {
|
|
2923
|
+
try {
|
|
2924
|
+
const correlationContext = getCorrelationContext();
|
|
2925
|
+
const statusCode = response.statusCode || 500;
|
|
2926
|
+
const metadata = {
|
|
2927
|
+
type: "http_error",
|
|
2928
|
+
method: request.method,
|
|
2929
|
+
url: request.url,
|
|
2930
|
+
statusCode,
|
|
2931
|
+
duration,
|
|
2932
|
+
correlationId: correlationContext?.correlationId,
|
|
2933
|
+
errorName: error?.name || "Error",
|
|
2934
|
+
errorMessage: error?.message || "Unknown error"
|
|
2935
|
+
};
|
|
2936
|
+
if (error?.stack) {
|
|
2937
|
+
metadata.trace = error.stack;
|
|
2938
|
+
}
|
|
2939
|
+
if (error?.response) {
|
|
2940
|
+
metadata.errorDetails = error.response;
|
|
2941
|
+
}
|
|
2942
|
+
const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${error?.message || "Unknown error"}`;
|
|
2943
|
+
this.logger.logWithMetadata("error", message, metadata);
|
|
2944
|
+
} catch (loggingError) {
|
|
2945
|
+
this.logger.error("Failed to log HTTP error", loggingError.stack);
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
};
|
|
2949
|
+
HttpLoggerInterceptor = _ts_decorate15([
|
|
2950
|
+
(0, import_common39.Injectable)(),
|
|
2951
|
+
_ts_param5(1, (0, import_common39.Optional)()),
|
|
2952
|
+
_ts_metadata8("design:type", Function),
|
|
2953
|
+
_ts_metadata8("design:paramtypes", [
|
|
2954
|
+
typeof LoggerService === "undefined" ? Object : LoggerService,
|
|
2955
|
+
typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
|
|
2956
|
+
])
|
|
2957
|
+
], HttpLoggerInterceptor);
|
|
2958
|
+
|
|
2959
|
+
// src/logger/logger.module.ts
|
|
2960
|
+
var import_common41 = require("@nestjs/common");
|
|
2961
|
+
|
|
2962
|
+
// src/logger/middleware/correlation-id.middleware.ts
|
|
2963
|
+
var import_common40 = require("@nestjs/common");
|
|
2964
|
+
function _ts_decorate16(decorators, target, key, desc) {
|
|
2965
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2966
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2967
|
+
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;
|
|
2968
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2969
|
+
}
|
|
2970
|
+
__name(_ts_decorate16, "_ts_decorate");
|
|
2971
|
+
function _ts_metadata9(k, v) {
|
|
2972
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2973
|
+
}
|
|
2974
|
+
__name(_ts_metadata9, "_ts_metadata");
|
|
2975
|
+
var CorrelationIdMiddleware = class {
|
|
2976
|
+
static {
|
|
2977
|
+
__name(this, "CorrelationIdMiddleware");
|
|
2978
|
+
}
|
|
2979
|
+
includeInResponse;
|
|
2980
|
+
responseHeader;
|
|
2981
|
+
constructor(options = {}) {
|
|
2982
|
+
this.includeInResponse = options.includeInResponse ?? true;
|
|
2983
|
+
this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;
|
|
2984
|
+
}
|
|
2985
|
+
/**
|
|
2986
|
+
* Middleware handler for processing requests.
|
|
2987
|
+
*/
|
|
2988
|
+
use(_req, reply, next) {
|
|
2989
|
+
const correlationId = generateCorrelationId();
|
|
2990
|
+
if (this.includeInResponse) {
|
|
2991
|
+
addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
|
|
2992
|
+
}
|
|
2993
|
+
runWithCorrelationContext({
|
|
2994
|
+
correlationId
|
|
2995
|
+
}, () => {
|
|
2996
|
+
next();
|
|
2997
|
+
});
|
|
2998
|
+
}
|
|
2999
|
+
/**
|
|
3000
|
+
* Fastify hook handler for onRequest.
|
|
3001
|
+
* This is an async function that returns a Promise, ensuring the AsyncLocalStorage
|
|
3002
|
+
* context persists throughout the entire request lifecycle.
|
|
3003
|
+
*/
|
|
3004
|
+
async onRequest(_req, reply) {
|
|
3005
|
+
const correlationId = generateCorrelationId();
|
|
3006
|
+
if (this.includeInResponse) {
|
|
3007
|
+
addCorrelationIdToResponse(reply, correlationId, this.responseHeader);
|
|
3008
|
+
}
|
|
3009
|
+
const store = correlationStorage.getStore();
|
|
3010
|
+
if (!store) {
|
|
3011
|
+
correlationStorage.enterWith({
|
|
3012
|
+
correlationId
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
};
|
|
3017
|
+
CorrelationIdMiddleware = _ts_decorate16([
|
|
3005
3018
|
(0, import_common40.Injectable)(),
|
|
3006
|
-
_ts_param5(0, (0, import_common40.Optional)()),
|
|
3007
|
-
_ts_param5(1, (0, import_common40.Optional)()),
|
|
3008
3019
|
_ts_metadata9("design:type", Function),
|
|
3009
3020
|
_ts_metadata9("design:paramtypes", [
|
|
3010
|
-
typeof
|
|
3011
|
-
typeof Logger === "undefined" ? Object : Logger
|
|
3021
|
+
typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
|
|
3012
3022
|
])
|
|
3013
|
-
],
|
|
3023
|
+
], CorrelationIdMiddleware);
|
|
3014
3024
|
|
|
3015
3025
|
// src/logger/logger.module.ts
|
|
3016
3026
|
function _ts_decorate17(decorators, target, key, desc) {
|
|
@@ -3133,9 +3143,9 @@ function createLoggerProviders(options = {}) {
|
|
|
3133
3143
|
providers.push(createDefaultLoggerProvider(mergedOptions));
|
|
3134
3144
|
}
|
|
3135
3145
|
providers.push({
|
|
3136
|
-
provide:
|
|
3146
|
+
provide: LoggerService,
|
|
3137
3147
|
useFactory: /* @__PURE__ */ __name((opts, defaultLogger) => {
|
|
3138
|
-
return new
|
|
3148
|
+
return new LoggerService(opts, defaultLogger);
|
|
3139
3149
|
}, "useFactory"),
|
|
3140
3150
|
inject: [
|
|
3141
3151
|
LOGGER_MODULE_OPTIONS,
|
|
@@ -3164,7 +3174,7 @@ function createLoggerProviders(options = {}) {
|
|
|
3164
3174
|
return new HttpLoggerInterceptor(logger, httpLoggerOptions);
|
|
3165
3175
|
}, "useFactory"),
|
|
3166
3176
|
inject: [
|
|
3167
|
-
|
|
3177
|
+
LoggerService,
|
|
3168
3178
|
LOGGER_MODULE_OPTIONS
|
|
3169
3179
|
]
|
|
3170
3180
|
});
|
|
@@ -3232,7 +3242,7 @@ var LoggerModule = class _LoggerModule {
|
|
|
3232
3242
|
module: _LoggerModule,
|
|
3233
3243
|
providers,
|
|
3234
3244
|
exports: [
|
|
3235
|
-
|
|
3245
|
+
LoggerService,
|
|
3236
3246
|
CorrelationIdMiddleware,
|
|
3237
3247
|
HttpLoggerInterceptor,
|
|
3238
3248
|
LOGGER_MODULE_OPTIONS
|
|
@@ -3309,9 +3319,9 @@ var LoggerModule = class _LoggerModule {
|
|
|
3309
3319
|
},
|
|
3310
3320
|
// Unified logger service
|
|
3311
3321
|
{
|
|
3312
|
-
provide:
|
|
3322
|
+
provide: LoggerService,
|
|
3313
3323
|
useFactory: /* @__PURE__ */ __name((opts, defaultLogger) => {
|
|
3314
|
-
return new
|
|
3324
|
+
return new LoggerService(opts, defaultLogger);
|
|
3315
3325
|
}, "useFactory"),
|
|
3316
3326
|
inject: [
|
|
3317
3327
|
LOGGER_MODULE_OPTIONS,
|
|
@@ -3342,13 +3352,13 @@ var LoggerModule = class _LoggerModule {
|
|
|
3342
3352
|
return new HttpLoggerInterceptor(logger, httpLoggerOptions);
|
|
3343
3353
|
}, "useFactory"),
|
|
3344
3354
|
inject: [
|
|
3345
|
-
|
|
3355
|
+
LoggerService,
|
|
3346
3356
|
LOGGER_MODULE_OPTIONS
|
|
3347
3357
|
]
|
|
3348
3358
|
}
|
|
3349
3359
|
],
|
|
3350
3360
|
exports: [
|
|
3351
|
-
|
|
3361
|
+
LoggerService,
|
|
3352
3362
|
CorrelationIdMiddleware,
|
|
3353
3363
|
HttpLoggerInterceptor,
|
|
3354
3364
|
LOGGER_MODULE_OPTIONS
|