@tumbaland/backend-core 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/.versionrc.json +7 -0
  2. package/README.md +179 -0
  3. package/__mocks__/uuid.js +8 -0
  4. package/dist/app/createBaseApp.d.ts +44 -0
  5. package/dist/app/createBaseApp.d.ts.map +1 -0
  6. package/dist/app/createBaseApp.js +54 -0
  7. package/dist/app/createBaseApp.js.map +1 -0
  8. package/dist/config/env.d.ts +8 -0
  9. package/dist/config/env.d.ts.map +1 -0
  10. package/dist/config/env.js +17 -0
  11. package/dist/config/env.js.map +1 -0
  12. package/dist/database/connection.d.ts +3 -0
  13. package/dist/database/connection.d.ts.map +1 -0
  14. package/dist/database/connection.js +49 -0
  15. package/dist/database/connection.js.map +1 -0
  16. package/dist/errors/HttpError.d.ts +32 -0
  17. package/dist/errors/HttpError.d.ts.map +1 -0
  18. package/dist/errors/HttpError.js +61 -0
  19. package/dist/errors/HttpError.js.map +1 -0
  20. package/dist/health/healthController.d.ts +21 -0
  21. package/dist/health/healthController.d.ts.map +1 -0
  22. package/dist/health/healthController.js +56 -0
  23. package/dist/health/healthController.js.map +1 -0
  24. package/dist/index.d.ts +20 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +81 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/logging/logger.d.ts +4 -0
  29. package/dist/logging/logger.d.ts.map +1 -0
  30. package/dist/logging/logger.js +78 -0
  31. package/dist/logging/logger.js.map +1 -0
  32. package/dist/metrics/index.d.ts +17 -0
  33. package/dist/metrics/index.d.ts.map +1 -0
  34. package/dist/metrics/index.js +99 -0
  35. package/dist/metrics/index.js.map +1 -0
  36. package/dist/middleware/authMiddleware.d.ts +9 -0
  37. package/dist/middleware/authMiddleware.d.ts.map +1 -0
  38. package/dist/middleware/authMiddleware.js +32 -0
  39. package/dist/middleware/authMiddleware.js.map +1 -0
  40. package/dist/middleware/corsMiddleware.d.ts +20 -0
  41. package/dist/middleware/corsMiddleware.d.ts.map +1 -0
  42. package/dist/middleware/corsMiddleware.js +33 -0
  43. package/dist/middleware/corsMiddleware.js.map +1 -0
  44. package/dist/middleware/errorHandler.d.ts +14 -0
  45. package/dist/middleware/errorHandler.d.ts.map +1 -0
  46. package/dist/middleware/errorHandler.js +88 -0
  47. package/dist/middleware/errorHandler.js.map +1 -0
  48. package/dist/middleware/requestLogger.d.ts +16 -0
  49. package/dist/middleware/requestLogger.d.ts.map +1 -0
  50. package/dist/middleware/requestLogger.js +49 -0
  51. package/dist/middleware/requestLogger.js.map +1 -0
  52. package/dist/middleware/security.d.ts +26 -0
  53. package/dist/middleware/security.d.ts.map +1 -0
  54. package/dist/middleware/security.js +47 -0
  55. package/dist/middleware/security.js.map +1 -0
  56. package/dist/middleware/validate.d.ts +11 -0
  57. package/dist/middleware/validate.d.ts.map +1 -0
  58. package/dist/middleware/validate.js +24 -0
  59. package/dist/middleware/validate.js.map +1 -0
  60. package/dist/tracing/index.d.ts +13 -0
  61. package/dist/tracing/index.d.ts.map +1 -0
  62. package/dist/tracing/index.js +89 -0
  63. package/dist/tracing/index.js.map +1 -0
  64. package/dist/types/auth.d.ts +32 -0
  65. package/dist/types/auth.d.ts.map +1 -0
  66. package/dist/types/auth.js +3 -0
  67. package/dist/types/auth.js.map +1 -0
  68. package/dist/utils/correlation.d.ts +11 -0
  69. package/dist/utils/correlation.d.ts.map +1 -0
  70. package/dist/utils/correlation.js +23 -0
  71. package/dist/utils/correlation.js.map +1 -0
  72. package/dist/utils/response.d.ts +24 -0
  73. package/dist/utils/response.d.ts.map +1 -0
  74. package/dist/utils/response.js +35 -0
  75. package/dist/utils/response.js.map +1 -0
  76. package/jest.config.js +14 -0
  77. package/package.json +61 -0
  78. package/src/app/createBaseApp.test.ts +69 -0
  79. package/src/app/createBaseApp.ts +75 -0
  80. package/src/config/env.test.ts +28 -0
  81. package/src/config/env.ts +13 -0
  82. package/src/database/connection.test.ts +142 -0
  83. package/src/database/connection.ts +46 -0
  84. package/src/errors/HttpError.test.ts +38 -0
  85. package/src/errors/HttpError.ts +57 -0
  86. package/src/health/healthController.test.ts +91 -0
  87. package/src/health/healthController.ts +56 -0
  88. package/src/index.ts +60 -0
  89. package/src/logging/logger.test.ts +76 -0
  90. package/src/logging/logger.ts +103 -0
  91. package/src/metrics/index.test.ts +91 -0
  92. package/src/metrics/index.ts +110 -0
  93. package/src/middleware/authMiddleware.test.ts +104 -0
  94. package/src/middleware/authMiddleware.ts +29 -0
  95. package/src/middleware/corsMiddleware.test.ts +58 -0
  96. package/src/middleware/corsMiddleware.ts +36 -0
  97. package/src/middleware/errorHandler.test.ts +146 -0
  98. package/src/middleware/errorHandler.ts +98 -0
  99. package/src/middleware/requestLogger.test.ts +81 -0
  100. package/src/middleware/requestLogger.ts +47 -0
  101. package/src/middleware/security.test.ts +45 -0
  102. package/src/middleware/security.ts +43 -0
  103. package/src/middleware/validate.test.ts +60 -0
  104. package/src/middleware/validate.ts +23 -0
  105. package/src/tracing/index.test.ts +250 -0
  106. package/src/tracing/index.ts +97 -0
  107. package/src/types/auth.ts +33 -0
  108. package/src/utils/correlation.test.ts +47 -0
  109. package/src/utils/correlation.ts +22 -0
  110. package/src/utils/response.test.ts +64 -0
  111. package/src/utils/response.ts +60 -0
  112. package/tsconfig.build.json +4 -0
  113. package/tsconfig.json +20 -0
package/dist/index.js ADDED
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ // @tumbaland/backend-core - Core shared functionality for Tumbaland backend services
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.extractSpanContext = exports.injectHeaders = exports.setSpanTag = exports.logToSpan = exports.createChildSpan = exports.tracingMiddleware = exports.startSpan = exports.getTracer = exports.initTracer = exports.register = exports.businessMetrics = exports.databaseQueriesTotal = exports.databaseQueryDuration = exports.httpRequestsTotal = exports.httpRequestDuration = exports.metricsMiddleware = exports.sendError = exports.sendSuccess = exports.createApiResponse = exports.correlationMiddleware = exports.generateCorrelationId = exports.validate = exports.strictRateLimiter = exports.standardRateLimiter = exports.createRateLimiter = exports.securityHeaders = exports.simpleRequestLogger = exports.requestLoggerWithMetrics = exports.requestLogger = exports.errorHandler = exports.createCorsMiddleware = exports.authenticateToken = exports.TooManyRequestsError = exports.ConflictError = exports.NotFoundError = exports.ForbiddenError = exports.UnauthorizedError = exports.BadRequestError = exports.HttpError = exports.requireEnv = exports.disconnectDB = exports.connectDB = exports.metricsHandler = exports.healthLive = exports.healthCheck = exports.logger = exports.createBaseApp = void 0;
8
+ // App bootstrap
9
+ var createBaseApp_1 = require("./app/createBaseApp");
10
+ Object.defineProperty(exports, "createBaseApp", { enumerable: true, get: function () { return createBaseApp_1.createBaseApp; } });
11
+ // Logging
12
+ var logger_1 = require("./logging/logger");
13
+ Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return __importDefault(logger_1).default; } });
14
+ // Health checks
15
+ var healthController_1 = require("./health/healthController");
16
+ Object.defineProperty(exports, "healthCheck", { enumerable: true, get: function () { return healthController_1.healthCheck; } });
17
+ Object.defineProperty(exports, "healthLive", { enumerable: true, get: function () { return healthController_1.healthLive; } });
18
+ Object.defineProperty(exports, "metricsHandler", { enumerable: true, get: function () { return healthController_1.metricsHandler; } });
19
+ // Database
20
+ var connection_1 = require("./database/connection");
21
+ Object.defineProperty(exports, "connectDB", { enumerable: true, get: function () { return connection_1.connectDB; } });
22
+ Object.defineProperty(exports, "disconnectDB", { enumerable: true, get: function () { return connection_1.disconnectDB; } });
23
+ // Config
24
+ var env_1 = require("./config/env");
25
+ Object.defineProperty(exports, "requireEnv", { enumerable: true, get: function () { return env_1.requireEnv; } });
26
+ // Errors
27
+ var HttpError_1 = require("./errors/HttpError");
28
+ Object.defineProperty(exports, "HttpError", { enumerable: true, get: function () { return HttpError_1.HttpError; } });
29
+ Object.defineProperty(exports, "BadRequestError", { enumerable: true, get: function () { return HttpError_1.BadRequestError; } });
30
+ Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return HttpError_1.UnauthorizedError; } });
31
+ Object.defineProperty(exports, "ForbiddenError", { enumerable: true, get: function () { return HttpError_1.ForbiddenError; } });
32
+ Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return HttpError_1.NotFoundError; } });
33
+ Object.defineProperty(exports, "ConflictError", { enumerable: true, get: function () { return HttpError_1.ConflictError; } });
34
+ Object.defineProperty(exports, "TooManyRequestsError", { enumerable: true, get: function () { return HttpError_1.TooManyRequestsError; } });
35
+ // Middleware
36
+ var authMiddleware_1 = require("./middleware/authMiddleware");
37
+ Object.defineProperty(exports, "authenticateToken", { enumerable: true, get: function () { return authMiddleware_1.authenticateToken; } });
38
+ var corsMiddleware_1 = require("./middleware/corsMiddleware");
39
+ Object.defineProperty(exports, "createCorsMiddleware", { enumerable: true, get: function () { return corsMiddleware_1.createCorsMiddleware; } });
40
+ var errorHandler_1 = require("./middleware/errorHandler");
41
+ Object.defineProperty(exports, "errorHandler", { enumerable: true, get: function () { return errorHandler_1.errorHandler; } });
42
+ var requestLogger_1 = require("./middleware/requestLogger");
43
+ Object.defineProperty(exports, "requestLogger", { enumerable: true, get: function () { return requestLogger_1.requestLogger; } });
44
+ Object.defineProperty(exports, "requestLoggerWithMetrics", { enumerable: true, get: function () { return requestLogger_1.requestLoggerWithMetrics; } });
45
+ Object.defineProperty(exports, "simpleRequestLogger", { enumerable: true, get: function () { return requestLogger_1.simpleRequestLogger; } });
46
+ var security_1 = require("./middleware/security");
47
+ Object.defineProperty(exports, "securityHeaders", { enumerable: true, get: function () { return security_1.securityHeaders; } });
48
+ Object.defineProperty(exports, "createRateLimiter", { enumerable: true, get: function () { return security_1.createRateLimiter; } });
49
+ Object.defineProperty(exports, "standardRateLimiter", { enumerable: true, get: function () { return security_1.standardRateLimiter; } });
50
+ Object.defineProperty(exports, "strictRateLimiter", { enumerable: true, get: function () { return security_1.strictRateLimiter; } });
51
+ var validate_1 = require("./middleware/validate");
52
+ Object.defineProperty(exports, "validate", { enumerable: true, get: function () { return validate_1.validate; } });
53
+ // Utils
54
+ var correlation_1 = require("./utils/correlation");
55
+ Object.defineProperty(exports, "generateCorrelationId", { enumerable: true, get: function () { return correlation_1.generateCorrelationId; } });
56
+ Object.defineProperty(exports, "correlationMiddleware", { enumerable: true, get: function () { return correlation_1.correlationMiddleware; } });
57
+ var response_1 = require("./utils/response");
58
+ Object.defineProperty(exports, "createApiResponse", { enumerable: true, get: function () { return response_1.createApiResponse; } });
59
+ Object.defineProperty(exports, "sendSuccess", { enumerable: true, get: function () { return response_1.sendSuccess; } });
60
+ Object.defineProperty(exports, "sendError", { enumerable: true, get: function () { return response_1.sendError; } });
61
+ // Metrics
62
+ var metrics_1 = require("./metrics");
63
+ Object.defineProperty(exports, "metricsMiddleware", { enumerable: true, get: function () { return metrics_1.metricsMiddleware; } });
64
+ Object.defineProperty(exports, "httpRequestDuration", { enumerable: true, get: function () { return metrics_1.httpRequestDuration; } });
65
+ Object.defineProperty(exports, "httpRequestsTotal", { enumerable: true, get: function () { return metrics_1.httpRequestsTotal; } });
66
+ Object.defineProperty(exports, "databaseQueryDuration", { enumerable: true, get: function () { return metrics_1.databaseQueryDuration; } });
67
+ Object.defineProperty(exports, "databaseQueriesTotal", { enumerable: true, get: function () { return metrics_1.databaseQueriesTotal; } });
68
+ Object.defineProperty(exports, "businessMetrics", { enumerable: true, get: function () { return metrics_1.businessMetrics; } });
69
+ Object.defineProperty(exports, "register", { enumerable: true, get: function () { return metrics_1.register; } });
70
+ // Tracing
71
+ var tracing_1 = require("./tracing");
72
+ Object.defineProperty(exports, "initTracer", { enumerable: true, get: function () { return tracing_1.initTracer; } });
73
+ Object.defineProperty(exports, "getTracer", { enumerable: true, get: function () { return tracing_1.getTracer; } });
74
+ Object.defineProperty(exports, "startSpan", { enumerable: true, get: function () { return tracing_1.startSpan; } });
75
+ Object.defineProperty(exports, "tracingMiddleware", { enumerable: true, get: function () { return tracing_1.tracingMiddleware; } });
76
+ Object.defineProperty(exports, "createChildSpan", { enumerable: true, get: function () { return tracing_1.createChildSpan; } });
77
+ Object.defineProperty(exports, "logToSpan", { enumerable: true, get: function () { return tracing_1.logToSpan; } });
78
+ Object.defineProperty(exports, "setSpanTag", { enumerable: true, get: function () { return tracing_1.setSpanTag; } });
79
+ Object.defineProperty(exports, "injectHeaders", { enumerable: true, get: function () { return tracing_1.injectHeaders; } });
80
+ Object.defineProperty(exports, "extractSpanContext", { enumerable: true, get: function () { return tracing_1.extractSpanContext; } });
81
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,qFAAqF;;;;;;AAErF,gBAAgB;AAChB,qDAAoD;AAA3C,8GAAA,aAAa,OAAA;AAGtB,UAAU;AACV,2CAAqD;AAA5C,iHAAA,OAAO,OAAU;AAE1B,gBAAgB;AAChB,8DAAoF;AAA3E,+GAAA,WAAW,OAAA;AAAE,8GAAA,UAAU,OAAA;AAAE,kHAAA,cAAc,OAAA;AAEhD,WAAW;AACX,oDAAgE;AAAvD,uGAAA,SAAS,OAAA;AAAE,0GAAA,YAAY,OAAA;AAEhC,SAAS;AACT,oCAA0C;AAAjC,iGAAA,UAAU,OAAA;AAEnB,SAAS;AACT,gDAAuJ;AAA9I,sGAAA,SAAS,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAE1H,aAAa;AACb,8DAAgE;AAAvD,mHAAA,iBAAiB,OAAA;AAC1B,8DAAmE;AAA1D,sHAAA,oBAAoB,OAAA;AAC7B,0DAAyD;AAAhD,4GAAA,YAAY,OAAA;AACrB,4DAA0G;AAAjG,8GAAA,aAAa,OAAA;AAAE,yHAAA,wBAAwB,OAAA;AAAE,oHAAA,mBAAmB,OAAA;AACrE,kDAAmH;AAA1G,2GAAA,eAAe,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AACnF,kDAAiD;AAAxC,oGAAA,QAAQ,OAAA;AAKjB,QAAQ;AACR,mDAAmF;AAA1E,oHAAA,qBAAqB,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AACrD,6CAA6E;AAApE,6GAAA,iBAAiB,OAAA;AAAE,uGAAA,WAAW,OAAA;AAAE,qGAAA,SAAS,OAAA;AAGlD,UAAU;AACV,qCAQmB;AAPjB,4GAAA,iBAAiB,OAAA;AACjB,8GAAA,mBAAmB,OAAA;AACnB,4GAAA,iBAAiB,OAAA;AACjB,gHAAA,qBAAqB,OAAA;AACrB,+GAAA,oBAAoB,OAAA;AACpB,0GAAA,eAAe,OAAA;AACf,mGAAA,QAAQ,OAAA;AAGV,UAAU;AACV,qCAUmB;AATjB,qGAAA,UAAU,OAAA;AACV,oGAAA,SAAS,OAAA;AACT,oGAAA,SAAS,OAAA;AACT,4GAAA,iBAAiB,OAAA;AACjB,0GAAA,eAAe,OAAA;AACf,oGAAA,SAAS,OAAA;AACT,qGAAA,UAAU,OAAA;AACV,wGAAA,aAAa,OAAA;AACb,6GAAA,kBAAkB,OAAA"}
@@ -0,0 +1,4 @@
1
+ import winston from 'winston';
2
+ declare const logger: winston.Logger;
3
+ export default logger;
4
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AA8E9B,QAAA,MAAM,MAAM,gBAsBV,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const winston_1 = __importDefault(require("winston"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ // Define log levels
10
+ const levels = {
11
+ error: 0,
12
+ warn: 1,
13
+ info: 2,
14
+ http: 3,
15
+ debug: 4,
16
+ };
17
+ const level = () => {
18
+ const env = process.env.NODE_ENV || 'development';
19
+ const isDevelopment = env === 'development';
20
+ return isDevelopment ? 'debug' : 'info';
21
+ };
22
+ // Define colors for each level
23
+ const colors = {
24
+ error: 'red',
25
+ warn: 'yellow',
26
+ info: 'green',
27
+ http: 'magenta',
28
+ debug: 'white',
29
+ };
30
+ winston_1.default.addColors(colors);
31
+ // Define format for console (human-readable)
32
+ const consoleFormat = winston_1.default.format.combine(winston_1.default.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }), winston_1.default.format.colorize({ all: true }), winston_1.default.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`));
33
+ // Define JSON format for production (structured logging)
34
+ const jsonFormat = winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.errors({ stack: true }), winston_1.default.format.json());
35
+ // Choose format based on environment
36
+ const isProduction = process.env.NODE_ENV === 'production';
37
+ const logFormat = isProduction ? jsonFormat : consoleFormat;
38
+ // Define which transports the logger must use
39
+ const transports = [
40
+ // Console transport (goes to Docker stdout/stderr)
41
+ new winston_1.default.transports.Console({
42
+ format: logFormat,
43
+ level: level()
44
+ }),
45
+ ];
46
+ // Add file transport only in development (optional)
47
+ if (!isProduction && process.env.LOG_TO_FILE === 'true') {
48
+ // Create logs directory if it doesn't exist
49
+ const logsDir = path_1.default.join(process.cwd(), 'logs');
50
+ if (!fs_1.default.existsSync(logsDir)) {
51
+ fs_1.default.mkdirSync(logsDir, { recursive: true });
52
+ }
53
+ transports.push(new winston_1.default.transports.File({
54
+ filename: path_1.default.join(logsDir, 'app.log'),
55
+ format: jsonFormat,
56
+ level: 'debug'
57
+ }));
58
+ }
59
+ // Create the logger instance
60
+ const logger = winston_1.default.createLogger({
61
+ level: level(),
62
+ levels,
63
+ format: logFormat,
64
+ transports,
65
+ // Handle exceptions and rejections
66
+ exceptionHandlers: [
67
+ new winston_1.default.transports.Console({
68
+ format: winston_1.default.format.combine(winston_1.default.format.colorize(), winston_1.default.format.simple())
69
+ })
70
+ ],
71
+ rejectionHandlers: [
72
+ new winston_1.default.transports.Console({
73
+ format: winston_1.default.format.combine(winston_1.default.format.colorize(), winston_1.default.format.simple())
74
+ })
75
+ ]
76
+ });
77
+ exports.default = logger;
78
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import promClient from 'prom-client';
2
+ declare const register: promClient.Registry<"text/plain; version=0.0.4; charset=utf-8">;
3
+ export declare const httpRequestDuration: promClient.Histogram<"route" | "method" | "status_code">;
4
+ export declare const httpRequestsTotal: promClient.Counter<"route" | "method" | "status_code">;
5
+ export declare const activeConnections: promClient.Gauge<string>;
6
+ export declare const databaseQueryDuration: promClient.Histogram<"operation" | "collection">;
7
+ export declare const databaseQueriesTotal: promClient.Counter<"operation" | "collection" | "status">;
8
+ export declare const businessMetrics: {
9
+ albumsCreated: promClient.Counter<string>;
10
+ filesUploaded: promClient.Counter<"file_type">;
11
+ usersRegistered: promClient.Counter<string>;
12
+ paymentsProcessed: promClient.Counter<"method" | "status">;
13
+ };
14
+ export declare const metricsHandler: (req: any, res: any) => Promise<void>;
15
+ export declare const metricsMiddleware: (req: any, res: any, next: any) => void;
16
+ export { register };
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,aAAa,CAAC;AAGrC,QAAA,MAAM,QAAQ,iEAA4B,CAAC;AAY3C,eAAO,MAAM,mBAAmB,0DAK9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,wDAI5B,CAAC;AAEH,eAAO,MAAM,iBAAiB,0BAG5B,CAAC;AAEH,eAAO,MAAM,qBAAqB,kDAKhC,CAAC;AAEH,eAAO,MAAM,oBAAoB,2DAI/B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;CAsB3B,CAAC;AAGF,eAAO,MAAM,cAAc,GAAU,KAAK,GAAG,EAAE,KAAK,GAAG,kBAQtD,CAAC;AAGF,eAAO,MAAM,iBAAiB,GAAI,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,SAyB9D,CAAC;AAEF,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.register = exports.metricsMiddleware = exports.metricsHandler = exports.businessMetrics = exports.databaseQueriesTotal = exports.databaseQueryDuration = exports.activeConnections = exports.httpRequestsTotal = exports.httpRequestDuration = void 0;
7
+ const prom_client_1 = __importDefault(require("prom-client"));
8
+ // Create a Registry which registers the metrics
9
+ const register = new prom_client_1.default.Registry();
10
+ exports.register = register;
11
+ // Add a default label which is added to all metrics
12
+ register.setDefaultLabels({
13
+ app: process.env.SERVICE_NAME || 'unknown-service',
14
+ version: process.env.npm_package_version || '1.0.0'
15
+ });
16
+ // Enable the collection of default metrics
17
+ prom_client_1.default.collectDefaultMetrics({ register });
18
+ // Custom metrics
19
+ exports.httpRequestDuration = new prom_client_1.default.Histogram({
20
+ name: 'http_request_duration_seconds',
21
+ help: 'Duration of HTTP requests in seconds',
22
+ labelNames: ['method', 'route', 'status_code'],
23
+ buckets: [0.1, 0.5, 1, 2, 5, 10]
24
+ });
25
+ exports.httpRequestsTotal = new prom_client_1.default.Counter({
26
+ name: 'http_requests_total',
27
+ help: 'Total number of HTTP requests',
28
+ labelNames: ['method', 'route', 'status_code']
29
+ });
30
+ exports.activeConnections = new prom_client_1.default.Gauge({
31
+ name: 'active_connections',
32
+ help: 'Number of active connections'
33
+ });
34
+ exports.databaseQueryDuration = new prom_client_1.default.Histogram({
35
+ name: 'database_query_duration_seconds',
36
+ help: 'Duration of database queries in seconds',
37
+ labelNames: ['operation', 'collection'],
38
+ buckets: [0.01, 0.05, 0.1, 0.5, 1, 2, 5]
39
+ });
40
+ exports.databaseQueriesTotal = new prom_client_1.default.Counter({
41
+ name: 'database_queries_total',
42
+ help: 'Total number of database queries',
43
+ labelNames: ['operation', 'collection', 'status']
44
+ });
45
+ exports.businessMetrics = {
46
+ albumsCreated: new prom_client_1.default.Counter({
47
+ name: 'albums_created_total',
48
+ help: 'Total number of albums created'
49
+ }),
50
+ filesUploaded: new prom_client_1.default.Counter({
51
+ name: 'files_uploaded_total',
52
+ help: 'Total number of files uploaded',
53
+ labelNames: ['file_type']
54
+ }),
55
+ usersRegistered: new prom_client_1.default.Counter({
56
+ name: 'users_registered_total',
57
+ help: 'Total number of users registered'
58
+ }),
59
+ paymentsProcessed: new prom_client_1.default.Counter({
60
+ name: 'payments_processed_total',
61
+ help: 'Total number of payments processed',
62
+ labelNames: ['status', 'method']
63
+ })
64
+ };
65
+ // Metrics endpoint handler
66
+ const metricsHandler = async (req, res) => {
67
+ try {
68
+ res.set('Content-Type', register.contentType);
69
+ const metrics = await register.metrics();
70
+ res.end(metrics);
71
+ }
72
+ catch (error) {
73
+ res.status(500).end('Error generating metrics');
74
+ }
75
+ };
76
+ exports.metricsHandler = metricsHandler;
77
+ // Middleware to collect HTTP metrics
78
+ const metricsMiddleware = (req, res, next) => {
79
+ const start = Date.now();
80
+ const { method, url } = req;
81
+ // Increment active connections
82
+ exports.activeConnections.inc();
83
+ res.on('finish', () => {
84
+ const duration = (Date.now() - start) / 1000; // Convert to seconds
85
+ const { statusCode } = res;
86
+ // Record metrics
87
+ exports.httpRequestDuration
88
+ .labels(method, url, statusCode.toString())
89
+ .observe(duration);
90
+ exports.httpRequestsTotal
91
+ .labels(method, url, statusCode.toString())
92
+ .inc();
93
+ // Decrement active connections
94
+ exports.activeConnections.dec();
95
+ });
96
+ next();
97
+ };
98
+ exports.metricsMiddleware = metricsMiddleware;
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ /**
3
+ * JWT authentication middleware
4
+ * Verifies JWT token and attaches user info (and its embedded groups) to
5
+ * the request — typed via the global `Express.Request` augmentation in
6
+ * `../types/auth`, no `(req as any)` cast needed.
7
+ */
8
+ export declare function authenticateToken(req: Request, res: Response, next: NextFunction): void;
9
+ //# sourceMappingURL=authMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAK1D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAiBvF"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.authenticateToken = authenticateToken;
7
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
+ const env_1 = require("../config/env");
9
+ /**
10
+ * JWT authentication middleware
11
+ * Verifies JWT token and attaches user info (and its embedded groups) to
12
+ * the request — typed via the global `Express.Request` augmentation in
13
+ * `../types/auth`, no `(req as any)` cast needed.
14
+ */
15
+ function authenticateToken(req, res, next) {
16
+ try {
17
+ const JWT_SECRET = (0, env_1.requireEnv)('JWT_SECRET');
18
+ const token = req.cookies?.access_token || req.headers.authorization?.replace('Bearer ', '');
19
+ if (!token) {
20
+ res.status(401).json({ success: false, message: 'Access token required' });
21
+ return;
22
+ }
23
+ const user = jsonwebtoken_1.default.verify(token, JWT_SECRET);
24
+ req.user = user;
25
+ req.userGroups = user.groups ?? [];
26
+ next();
27
+ }
28
+ catch (error) {
29
+ res.status(401).json({ success: false, message: 'Invalid or expired token' });
30
+ }
31
+ }
32
+ //# sourceMappingURL=authMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authMiddleware.js","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":";;;;;AAWA,8CAiBC;AA3BD,gEAA+B;AAC/B,uCAA2C;AAG3C;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC/E,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAA,gBAAU,EAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAE7F,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAgB,CAAC;QAC1D,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChB,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;QACnC,IAAI,EAAE,CAAC;IACT,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,CAAC;IAChF,CAAC;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ import cors from 'cors';
2
+ export interface CorsMiddlewareOptions {
3
+ /**
4
+ * Comma-separated origin whitelist. Defaults to process.env.CORS_ORIGIN,
5
+ * read per-request so it works regardless of dotenv.config() timing.
6
+ */
7
+ origins?: string;
8
+ exposedHeaders?: string[];
9
+ }
10
+ /**
11
+ * Shared CORS middleware with an explicit origin whitelist.
12
+ * Requests without an Origin header (server-to-server, curl, health checks)
13
+ * are always allowed; browser requests must match the whitelist.
14
+ */
15
+ export declare function createCorsMiddleware(options?: CorsMiddlewareOptions): (req: cors.CorsRequest, res: {
16
+ statusCode?: number | undefined;
17
+ setHeader(key: string, value: string): any;
18
+ end(): any;
19
+ }, next: (err?: any) => any) => void;
20
+ //# sourceMappingURL=corsMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corsMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/corsMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,qBAA0B;cAmBiE,CAAC;;;aAAmH,CAAC,uBAD7P"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createCorsMiddleware = createCorsMiddleware;
7
+ const cors_1 = __importDefault(require("cors"));
8
+ const logger_1 = __importDefault(require("../logging/logger"));
9
+ /**
10
+ * Shared CORS middleware with an explicit origin whitelist.
11
+ * Requests without an Origin header (server-to-server, curl, health checks)
12
+ * are always allowed; browser requests must match the whitelist.
13
+ */
14
+ function createCorsMiddleware(options = {}) {
15
+ return (0, cors_1.default)({
16
+ origin: (origin, callback) => {
17
+ const allowedOrigins = (options.origins ?? process.env.CORS_ORIGIN ?? '')
18
+ .split(',')
19
+ .map(o => o.trim())
20
+ .filter(Boolean);
21
+ if (!origin || allowedOrigins.includes(origin)) {
22
+ return callback(null, true);
23
+ }
24
+ logger_1.default.warn('Blocked CORS origin', { origin });
25
+ return callback(new Error('Not allowed by CORS: ' + origin));
26
+ },
27
+ credentials: true,
28
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
29
+ allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'x-correlation-id', 'x-session-id'],
30
+ exposedHeaders: options.exposedHeaders
31
+ });
32
+ }
33
+ //# sourceMappingURL=corsMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corsMiddleware.js","sourceRoot":"","sources":["../../src/middleware/corsMiddleware.ts"],"names":[],"mappings":";;;;;AAiBA,oDAkBC;AAnCD,gDAAwB;AACxB,+DAAuC;AAWvC;;;;GAIG;AACH,SAAgB,oBAAoB,CAAC,UAAiC,EAAE;IACtE,OAAO,IAAA,cAAI,EAAC;QACV,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;YAC3B,MAAM,cAAc,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;iBACtE,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBAClB,MAAM,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/C,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC9B,CAAC;YACD,gBAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/C,OAAO,QAAQ,CAAC,IAAI,KAAK,CAAC,uBAAuB,GAAG,MAAM,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,WAAW,EAAE,IAAI;QACjB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC;QACpD,cAAc,EAAE,CAAC,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,CAAC;QACzG,cAAc,EAAE,OAAO,CAAC,cAAc;KACvC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { ErrorRequestHandler } from 'express';
2
+ /**
3
+ * Global error handler middleware.
4
+ *
5
+ * Controllers throw a typed `HttpError` (BadRequestError, NotFoundError,
6
+ * ForbiddenError, ...) instead of hand-rolling try/catch + string-matching
7
+ * on `error.message` to pick a status code — Express 5 forwards rejected
8
+ * promises from async route handlers here automatically. Anything that
9
+ * isn't a recognized error type is treated as an unexpected bug: logged
10
+ * with its full stack and returned as a generic 500 (no message leak
11
+ * outside development), same as before this file knew about HttpError.
12
+ */
13
+ export declare const errorHandler: ErrorRequestHandler;
14
+ //# sourceMappingURL=errorHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/middleware/errorHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,mBAAmB,EAAE,MAAM,SAAS,CAAC;AA4B/E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,EAAE,mBA0D1B,CAAC"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.errorHandler = void 0;
7
+ const logger_1 = __importDefault(require("../logging/logger"));
8
+ const HttpError_1 = require("../errors/HttpError");
9
+ /**
10
+ * Recognizes error shapes that map to an obvious HTTP status without a
11
+ * controller having to catch and re-throw them: our own typed HttpError
12
+ * hierarchy, plus Mongoose's ValidationError (failed schema validation,
13
+ * e.g. a missing required field) and CastError (e.g. an invalid ObjectId
14
+ * string) — both of which are client mistakes, not server bugs, but throw
15
+ * as plain Mongoose error classes rather than anything of ours.
16
+ */
17
+ function classifyError(error) {
18
+ if (error instanceof HttpError_1.HttpError) {
19
+ return { statusCode: error.statusCode, name: error.name, message: error.message };
20
+ }
21
+ if (error.name === 'ValidationError' || error.name === 'CastError') {
22
+ return { statusCode: 400, name: error.name, message: error.message };
23
+ }
24
+ return null;
25
+ }
26
+ /**
27
+ * Global error handler middleware.
28
+ *
29
+ * Controllers throw a typed `HttpError` (BadRequestError, NotFoundError,
30
+ * ForbiddenError, ...) instead of hand-rolling try/catch + string-matching
31
+ * on `error.message` to pick a status code — Express 5 forwards rejected
32
+ * promises from async route handlers here automatically. Anything that
33
+ * isn't a recognized error type is treated as an unexpected bug: logged
34
+ * with its full stack and returned as a generic 500 (no message leak
35
+ * outside development), same as before this file knew about HttpError.
36
+ */
37
+ const errorHandler = (error, req, res, _next) => {
38
+ const known = classifyError(error);
39
+ if (known) {
40
+ // Client errors (4xx) are routine, expected control flow — log without
41
+ // a stack trace at warn level, not as if the service were broken.
42
+ logger_1.default.warn('Request failed:', {
43
+ error: known.message,
44
+ statusCode: known.statusCode,
45
+ url: req.url,
46
+ method: req.method,
47
+ correlationId: req.correlationId
48
+ });
49
+ }
50
+ else {
51
+ logger_1.default.error('Unhandled error:', {
52
+ error: error.message,
53
+ stack: error.stack,
54
+ url: req.url,
55
+ method: req.method,
56
+ ip: req.ip,
57
+ userAgent: req.get('User-Agent'),
58
+ correlationId: req.correlationId
59
+ });
60
+ }
61
+ // Add CORS headers to error responses
62
+ const origin = req.headers.origin;
63
+ if (origin && (origin.includes('localhost') || origin.includes('tumbaland.eu'))) {
64
+ res.header('Access-Control-Allow-Origin', origin);
65
+ res.header('Access-Control-Allow-Credentials', 'true');
66
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
67
+ res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, x-correlation-id, x-session-id');
68
+ }
69
+ if (known) {
70
+ res.status(known.statusCode).json({
71
+ success: false,
72
+ error: known.name,
73
+ message: known.message
74
+ });
75
+ return;
76
+ }
77
+ // Don't leak error details in production for unexpected errors
78
+ const isDevelopment = process.env.NODE_ENV === 'development';
79
+ const errorMessage = isDevelopment ? error.message : 'Something went wrong';
80
+ res.status(500).json({
81
+ success: false,
82
+ error: 'Internal server error',
83
+ message: errorMessage,
84
+ ...(isDevelopment && { stack: error.stack })
85
+ });
86
+ };
87
+ exports.errorHandler = errorHandler;
88
+ //# sourceMappingURL=errorHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/middleware/errorHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Morgan middleware configured to use Winston logger
3
+ * Logs HTTP requests in structured format
4
+ */
5
+ export declare const requestLogger: (req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse<import("node:http").IncomingMessage>, callback: (err?: Error) => void) => void;
6
+ /**
7
+ * Combined middleware that includes both logging and metrics
8
+ * Use this instead of separate requestLogger and metricsMiddleware
9
+ */
10
+ export declare const requestLoggerWithMetrics: ((req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse<import("node:http").IncomingMessage>, callback: (err?: Error) => void) => void)[];
11
+ /**
12
+ * Simple request logger for development
13
+ * Logs basic request info with correlation ID
14
+ */
15
+ export declare const simpleRequestLogger: (req: any, res: any, next: any) => void;
16
+ //# sourceMappingURL=requestLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestLogger.d.ts","sourceRoot":"","sources":["../../src/middleware/requestLogger.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,eAAO,MAAM,aAAa,yIAFU,CAAC,yBAQnC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,wBAAwB,0IAdD,CAAC,4BAcqC,CAAC;AAE3E;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,SAoBhE,CAAC"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.simpleRequestLogger = exports.requestLoggerWithMetrics = exports.requestLogger = void 0;
7
+ const morgan_1 = __importDefault(require("morgan"));
8
+ const logger_1 = __importDefault(require("../logging/logger"));
9
+ const metrics_1 = require("../metrics");
10
+ /**
11
+ * Morgan middleware configured to use Winston logger
12
+ * Logs HTTP requests in structured format
13
+ */
14
+ exports.requestLogger = (0, morgan_1.default)('combined', {
15
+ stream: {
16
+ write: (message) => {
17
+ logger_1.default.http(message.trim());
18
+ }
19
+ }
20
+ });
21
+ /**
22
+ * Combined middleware that includes both logging and metrics
23
+ * Use this instead of separate requestLogger and metricsMiddleware
24
+ */
25
+ exports.requestLoggerWithMetrics = [exports.requestLogger, metrics_1.metricsMiddleware];
26
+ /**
27
+ * Simple request logger for development
28
+ * Logs basic request info with correlation ID
29
+ */
30
+ const simpleRequestLogger = (req, res, next) => {
31
+ const start = Date.now();
32
+ const correlationId = req.correlationId || 'unknown';
33
+ logger_1.default.info(`→ ${req.method} ${req.url}`, {
34
+ correlationId,
35
+ ip: req.ip,
36
+ userAgent: req.get('User-Agent')
37
+ });
38
+ res.on('finish', () => {
39
+ const duration = Date.now() - start;
40
+ logger_1.default.info(`← ${req.method} ${req.url} ${res.statusCode} ${duration}ms`, {
41
+ correlationId,
42
+ statusCode: res.statusCode,
43
+ duration
44
+ });
45
+ });
46
+ next();
47
+ };
48
+ exports.simpleRequestLogger = simpleRequestLogger;
49
+ //# sourceMappingURL=requestLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestLogger.js","sourceRoot":"","sources":["../../src/middleware/requestLogger.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAC5B,+DAAuC;AACvC,wCAA+C;AAE/C;;;GAGG;AACU,QAAA,aAAa,GAAG,IAAA,gBAAM,EAAC,UAAU,EAAE;IAC9C,MAAM,EAAE;QACN,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE;YACzB,gBAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9B,CAAC;KACF;CACF,CAAC,CAAC;AAEH;;;GAGG;AACU,QAAA,wBAAwB,GAAG,CAAC,qBAAa,EAAE,2BAAiB,CAAC,CAAC;AAE3E;;;GAGG;AACI,MAAM,mBAAmB,GAAG,CAAC,GAAQ,EAAE,GAAQ,EAAE,IAAS,EAAE,EAAE;IACnE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC;IAErD,gBAAM,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,EAAE;QACxC,aAAa;QACb,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;KACjC,CAAC,CAAC;IAEH,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACpC,gBAAM,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,IAAI,QAAQ,IAAI,EAAE;YACxE,aAAa;YACb,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,QAAQ;SACT,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,EAAE,CAAC;AACT,CAAC,CAAC;AApBW,QAAA,mBAAmB,uBAoB9B"}