nestjs-telescope
Version:
A debugging and monitoring tool for NestJS applications, inspired by Laravel Telescope
157 lines • 6.83 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelescopeInterceptor = void 0;
const common_1 = require("@nestjs/common");
const operators_1 = require("rxjs/operators");
const telescope_service_1 = require("./telescope.service");
let TelescopeInterceptor = class TelescopeInterceptor {
constructor(telescopeService) {
this.telescopeService = telescopeService;
}
intercept(context, next) {
const request = context.switchToHttp().getRequest();
const response = context.switchToHttp().getResponse();
const startTime = Date.now();
const method = request.method;
const path = request.url;
if (path.startsWith('/telescope')) {
return next.handle();
}
if (this.shouldSkipRequest(request)) {
return next.handle();
}
return next.handle().pipe((0, operators_1.tap)((responseBody) => {
const duration = Date.now() - startTime;
const status = response.statusCode;
const requestDetails = {
method: request.method || 'UNKNOWN',
url: request.url || '',
path: request.path || request.url || '',
query: request.query || {},
params: request.params || {},
headers: this.sanitizeHeaders(request.headers || {}),
cookies: request.cookies || {},
body: this.sanitizeBody(request.body),
ip: this.getClientIP(request),
userAgent: request.headers?.['user-agent'] || 'Unknown',
referer: request.headers?.referer,
origin: request.headers?.origin,
hostname: request.hostname || request.headers?.host || 'Unknown',
protocol: request.protocol || 'http',
timestamp: new Date(),
};
const responseDetails = {
statusCode: status,
statusMessage: response.statusMessage || 'OK',
headers: this.sanitizeHeaders(response.getHeaders()),
body: this.sanitizeBody(responseBody),
responseTime: duration,
};
this.telescopeService.addDetailedRequestEntry(requestDetails, responseDetails);
}), (0, operators_1.catchError)((error) => {
const duration = Date.now() - startTime;
const status = error.status || 500;
const requestDetails = {
method: request.method || 'UNKNOWN',
url: request.url || '',
path: request.path || request.url || '',
query: request.query || {},
params: request.params || {},
headers: this.sanitizeHeaders(request.headers || {}),
cookies: request.cookies || {},
body: this.sanitizeBody(request.body),
ip: this.getClientIP(request),
userAgent: request.headers?.['user-agent'] || 'Unknown',
referer: request.headers?.referer,
origin: request.headers?.origin,
hostname: request.hostname || request.headers?.host || 'Unknown',
protocol: request.protocol || 'http',
timestamp: new Date(),
};
this.telescopeService.addDetailedExceptionEntry({
name: error.name || 'Unknown Error',
message: error.message || 'Unknown error',
stack: error.stack,
statusCode: status,
timestamp: new Date(),
}, requestDetails);
throw error;
}));
}
shouldSkipRequest(request) {
const skipPaths = [
'/.well-known/appspecific/com.chrome.devtools.json',
'/favicon.ico',
'/robots.txt',
'/sitemap.xml',
'/.well-known/',
'/__webpack_hmr',
'/hot-update.json'
];
return skipPaths.some(path => request.url.startsWith(path));
}
getClientIP(request) {
const xForwardedFor = request.headers['x-forwarded-for'];
const forwardedIP = xForwardedFor ? xForwardedFor.split(',')[0]?.trim() : null;
return request.ip ||
request.connection?.remoteAddress ||
request.socket?.remoteAddress ||
forwardedIP ||
request.headers['x-real-ip'] ||
'Unknown';
}
sanitizeHeaders(headers) {
const sanitized = {};
const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-auth-token'];
if (!headers || typeof headers !== 'object') {
return sanitized;
}
for (const [key, value] of Object.entries(headers)) {
if (key && sensitiveHeaders.includes(key.toLowerCase())) {
sanitized[key] = '[REDACTED]';
}
else if (key && value !== undefined && value !== null) {
sanitized[key] = String(value);
}
}
return sanitized;
}
sanitizeBody(body) {
if (!body)
return null;
if (typeof body === 'string') {
try {
body = JSON.parse(body);
}
catch {
return body;
}
}
if (typeof body === 'object' && body !== null) {
const sanitized = { ...body };
const sensitiveFields = ['password', 'token', 'secret', 'key', 'api_key', 'auth'];
for (const field of sensitiveFields) {
if (sanitized[field]) {
sanitized[field] = '[REDACTED]';
}
}
return sanitized;
}
return body;
}
};
exports.TelescopeInterceptor = TelescopeInterceptor;
exports.TelescopeInterceptor = TelescopeInterceptor = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [telescope_service_1.TelescopeService])
], TelescopeInterceptor);
//# sourceMappingURL=telescope.interceptor.js.map
;