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