@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
@@ -0,0 +1,7 @@
1
+ {
2
+ "skip": {
3
+ "changelog": true,
4
+ "commit": true,
5
+ "tag": true
6
+ }
7
+ }
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # @tumbaland/backend-core
2
+
3
+ Core shared functionality for Tumbaland backend services.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @tumbaland/backend-core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Service Setup
14
+
15
+ ```typescript
16
+ import express from 'express';
17
+ import {
18
+ logger,
19
+ healthCheck,
20
+ connectDB,
21
+ requestLogger,
22
+ errorHandler,
23
+ correlationMiddleware
24
+ } from '@tumbaland/backend-core';
25
+
26
+ const app = express();
27
+
28
+ // Environment variables
29
+ process.env.SERVICE_NAME = 'my-service';
30
+ process.env.SERVICE_DESCRIPTION = 'My awesome service';
31
+
32
+ // Middleware
33
+ app.use(correlationMiddleware);
34
+ app.use(requestLogger);
35
+
36
+ // Routes
37
+ app.get('/health', healthCheck);
38
+
39
+ // Error handling (must be last)
40
+ app.use(errorHandler);
41
+
42
+ // Start server
43
+ connectDB()
44
+ .then(() => {
45
+ const PORT = process.env.PORT || 3000;
46
+ app.listen(PORT, () => {
47
+ logger.info(`🚀 Service running on port ${PORT}`);
48
+ });
49
+ })
50
+ .catch((error) => {
51
+ logger.error('Failed to start service:', error);
52
+ process.exit(1);
53
+ });
54
+ ```
55
+
56
+ ### Using Authentication
57
+
58
+ ```typescript
59
+ import { authenticateToken } from '@tumbaland/backend-core';
60
+
61
+ app.get('/protected', authenticateToken, (req, res) => {
62
+ const user = (req as any).user;
63
+ res.json({ message: `Hello ${user.name}!` });
64
+ });
65
+ ```
66
+
67
+ ### Structured Logging
68
+
69
+ ```typescript
70
+ import { logger } from '@tumbaland/backend-core';
71
+
72
+ // Different log levels
73
+ logger.error('Database connection failed', { error: err.message });
74
+ logger.warn('High memory usage detected', { usage: '85%' });
75
+ logger.info('User logged in', { userId: '123', ip: '192.168.1.1' });
76
+ logger.debug('Processing request', { correlationId: req.correlationId });
77
+ ```
78
+
79
+ ### API Responses
80
+
81
+ ```typescript
82
+ import { sendSuccess, sendError } from '@tumbaland/backend-core';
83
+
84
+ app.get('/api/users', (req, res) => {
85
+ // Success response
86
+ sendSuccess(res, users, 'Users retrieved successfully');
87
+
88
+ // Error response
89
+ sendError(res, 'Failed to retrieve users', 500, 'Database error');
90
+ });
91
+ ```
92
+
93
+ ## Environment Variables
94
+
95
+ - `NODE_ENV`: `development` or `production`
96
+ - `SERVICE_NAME`: Name of your service
97
+ - `SERVICE_DESCRIPTION`: Description of your service
98
+ - `LOG_TO_FILE`: Set to `true` to also log to files (development only)
99
+
100
+ ## Docker Logging
101
+
102
+ This library is optimized for Docker deployments:
103
+
104
+ - Logs to stdout/stderr by default
105
+ - Use structured JSON in production
106
+ - Integrates with Docker logging drivers
107
+ - Compatible with log aggregation tools (ELK, Loki, etc.)
108
+
109
+ ## Development vs Production
110
+
111
+ ### Development
112
+ - Colored console output
113
+ - Debug level logging
114
+ - Human-readable format
115
+
116
+ ### Production
117
+ - JSON structured logging
118
+ - Info level and above
119
+ - Optimized for log aggregation
120
+
121
+ ## 📦 Releases & Versioning
122
+
123
+ This library uses [standard-version](https://github.com/conventional-changelog/standard-version) for automated versioning and follows [Conventional Commits](https://conventionalcommits.org/) specification.
124
+
125
+ ### Release Types
126
+
127
+ - **PATCH** (`1.0.0` → `1.0.1`): Bug fixes
128
+ - **MINOR** (`1.0.0` → `1.1.0`): New features (backward compatible)
129
+ - **MAJOR** (`1.0.0` → `2.0.0`): Breaking changes
130
+
131
+ ### Commit Message Format
132
+
133
+ ```
134
+ type(scope): description
135
+
136
+ [optional body]
137
+
138
+ [optional footer]
139
+ ```
140
+
141
+ **Types:**
142
+ - `feat`: New feature
143
+ - `fix`: Bug fix
144
+ - `docs`: Documentation
145
+ - `style`: Code style changes
146
+ - `refactor`: Code refactoring
147
+ - `test`: Testing
148
+ - `chore`: Maintenance
149
+
150
+ **Examples:**
151
+ ```
152
+ feat(auth): add JWT token refresh
153
+ fix(logging): resolve memory leak in Winston transport
154
+ docs(api): update health check endpoint documentation
155
+ ```
156
+
157
+ ### Release Process
158
+
159
+ 1. **Make changes** with conventional commit messages
160
+ 2. **Run release script**: `./release.sh`
161
+ 3. **Push changes**: `git push origin main`
162
+ 4. **Publish**: Automated via GitHub Actions
163
+
164
+ ### Changelog
165
+
166
+ Changelogs are maintained at the project level in the root `CHANGELOG.md` file. Individual library changelogs are not generated to maintain consistency across the monorepo.
167
+
168
+ ### Beta Releases
169
+
170
+ For beta releases: `npm run release:beta`
171
+
172
+ ---
173
+
174
+ ## Contributing
175
+
176
+ 1. Make changes to source files in `src/`
177
+ 2. Run `npm run build` to compile TypeScript
178
+ 3. Test your changes
179
+ 4. Submit a pull request
@@ -0,0 +1,8 @@
1
+ // Jest's CJS module loader can't require the real `uuid` package (ESM-only
2
+ // since v9) — Node itself supports require(esm) at runtime, but Jest doesn't.
3
+ // Swap in Node's built-in UUID generator for tests only.
4
+ const crypto = require('crypto');
5
+
6
+ module.exports = {
7
+ v4: () => crypto.randomUUID()
8
+ };
@@ -0,0 +1,44 @@
1
+ import { Express, RequestHandler } from 'express';
2
+ import { CorsMiddlewareOptions } from '../middleware/corsMiddleware';
3
+ export interface CreateBaseAppOptions {
4
+ /** Passed through to createCorsMiddleware. */
5
+ corsOptions?: CorsMiddlewareOptions;
6
+ /**
7
+ * Defaults to standardRateLimiter; pass strictRateLimiter or a custom one
8
+ * to override. Pass `false` to skip mounting one here entirely — e.g. when
9
+ * a route (like a webhook) must be registered, and therefore exempted,
10
+ * before the limiter, and the service applies it itself afterward.
11
+ */
12
+ rateLimiter?: RequestHandler | false;
13
+ /** Mount express.json() here. Set false when a route needs the raw body first (e.g. a webhook) or handles its own parsing. Default true. */
14
+ parseJson?: boolean;
15
+ /** Mount cookie-parser here. Set false for services that don't use cookies. Default true. */
16
+ parseCookies?: boolean;
17
+ /** Mount tracingMiddleware. Default true. */
18
+ tracing?: boolean;
19
+ /** Use requestLoggerWithMetrics (adds Prometheus histograms) instead of the plain requestLogger. Default true. */
20
+ metrics?: boolean;
21
+ }
22
+ /**
23
+ * Assembles the middleware stack every service was hand-rolling in its own
24
+ * index.ts (correlation → tracing → request logging → security → rate
25
+ * limiting → CORS → cookies → JSON body). Services still mount their own
26
+ * routes, `/health` (DB-aware readiness), `/metrics`, and
27
+ * `app.use(errorHandler)` last — this only owns the common prefix, not the
28
+ * whole app lifecycle.
29
+ *
30
+ * `/health/live` is the one exception: it's mounted here, first, ahead of
31
+ * every other middleware. It has zero per-service variation (it never
32
+ * touches a dependency, just confirms the process is up), so — unlike
33
+ * `/health` — there's nothing for a service to customize. Mounting it
34
+ * before the rate limiter also matters operationally: a service under
35
+ * heavy legitimate traffic shouldn't have its own liveness probe start
36
+ * getting 429s and get killed for being "unhealthy" at the exact moment
37
+ * it's just busy.
38
+ *
39
+ * Services with non-standard body parsing (a webhook needing the raw body,
40
+ * or conditional parsing per-route) should pass `parseJson`/`parseCookies:
41
+ * false` and mount those themselves at the exact point they need to.
42
+ */
43
+ export declare function createBaseApp(options?: CreateBaseAppOptions): Express;
44
+ //# sourceMappingURL=createBaseApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createBaseApp.d.ts","sourceRoot":"","sources":["../../src/app/createBaseApp.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK3D,OAAO,EAAwB,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAI3F,MAAM,WAAW,oBAAoB;IACnC,8CAA8C;IAC9C,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC;IACrC,4IAA4I;IAC5I,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6FAA6F;IAC7F,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kHAAkH;IAClH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAwBzE"}
@@ -0,0 +1,54 @@
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.createBaseApp = createBaseApp;
7
+ const express_1 = __importDefault(require("express"));
8
+ const cookie_parser_1 = __importDefault(require("cookie-parser"));
9
+ const correlation_1 = require("../utils/correlation");
10
+ const tracing_1 = require("../tracing");
11
+ const requestLogger_1 = require("../middleware/requestLogger");
12
+ const corsMiddleware_1 = require("../middleware/corsMiddleware");
13
+ const security_1 = require("../middleware/security");
14
+ const healthController_1 = require("../health/healthController");
15
+ /**
16
+ * Assembles the middleware stack every service was hand-rolling in its own
17
+ * index.ts (correlation → tracing → request logging → security → rate
18
+ * limiting → CORS → cookies → JSON body). Services still mount their own
19
+ * routes, `/health` (DB-aware readiness), `/metrics`, and
20
+ * `app.use(errorHandler)` last — this only owns the common prefix, not the
21
+ * whole app lifecycle.
22
+ *
23
+ * `/health/live` is the one exception: it's mounted here, first, ahead of
24
+ * every other middleware. It has zero per-service variation (it never
25
+ * touches a dependency, just confirms the process is up), so — unlike
26
+ * `/health` — there's nothing for a service to customize. Mounting it
27
+ * before the rate limiter also matters operationally: a service under
28
+ * heavy legitimate traffic shouldn't have its own liveness probe start
29
+ * getting 429s and get killed for being "unhealthy" at the exact moment
30
+ * it's just busy.
31
+ *
32
+ * Services with non-standard body parsing (a webhook needing the raw body,
33
+ * or conditional parsing per-route) should pass `parseJson`/`parseCookies:
34
+ * false` and mount those themselves at the exact point they need to.
35
+ */
36
+ function createBaseApp(options = {}) {
37
+ const { corsOptions, rateLimiter = security_1.standardRateLimiter, parseJson = true, parseCookies = true, tracing = true, metrics = true } = options;
38
+ const app = (0, express_1.default)();
39
+ app.get('/health/live', healthController_1.healthLive);
40
+ app.use(security_1.securityHeaders);
41
+ if (rateLimiter)
42
+ app.use(rateLimiter);
43
+ app.use(correlation_1.correlationMiddleware);
44
+ if (tracing)
45
+ app.use(tracing_1.tracingMiddleware);
46
+ app.use(metrics ? requestLogger_1.requestLoggerWithMetrics : requestLogger_1.requestLogger);
47
+ app.use((0, corsMiddleware_1.createCorsMiddleware)(corsOptions));
48
+ if (parseCookies)
49
+ app.use((0, cookie_parser_1.default)());
50
+ if (parseJson)
51
+ app.use(express_1.default.json());
52
+ return app;
53
+ }
54
+ //# sourceMappingURL=createBaseApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createBaseApp.js","sourceRoot":"","sources":["../../src/app/createBaseApp.ts"],"names":[],"mappings":";;;;;AAkDA,sCAwBC;AA1ED,sDAA2D;AAC3D,kEAAyC;AACzC,sDAA6D;AAC7D,wCAA+C;AAC/C,+DAAsF;AACtF,iEAA2F;AAC3F,qDAA8E;AAC9E,iEAAwD;AAsBxD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,aAAa,CAAC,UAAgC,EAAE;IAC9D,MAAM,EACJ,WAAW,EACX,WAAW,GAAG,8BAAmB,EACjC,SAAS,GAAG,IAAI,EAChB,YAAY,GAAG,IAAI,EACnB,OAAO,GAAG,IAAI,EACd,OAAO,GAAG,IAAI,EACf,GAAG,OAAO,CAAC;IAEZ,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;IAEtB,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,6BAAU,CAAC,CAAC;IAEpC,GAAG,CAAC,GAAG,CAAC,0BAAe,CAAC,CAAC;IACzB,IAAI,WAAW;QAAE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtC,GAAG,CAAC,GAAG,CAAC,mCAAqB,CAAC,CAAC;IAC/B,IAAI,OAAO;QAAE,GAAG,CAAC,GAAG,CAAC,2BAAiB,CAAC,CAAC;IACxC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwB,CAAC,CAAC,CAAC,6BAAa,CAAC,CAAC;IAC5D,GAAG,CAAC,GAAG,CAAC,IAAA,qCAAoB,EAAC,WAAW,CAAC,CAAC,CAAC;IAC3C,IAAI,YAAY;QAAE,GAAG,CAAC,GAAG,CAAC,IAAA,uBAAY,GAAE,CAAC,CAAC;IAC1C,IAAI,SAAS;QAAE,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAEvC,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns the value of a required environment variable.
3
+ * Throws if the variable is missing or empty — call at service startup
4
+ * (after dotenv.config()) so misconfigured services fail fast instead of
5
+ * running with insecure defaults.
6
+ */
7
+ export declare function requireEnv(name: string): string;
8
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/config/env.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM/C"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireEnv = requireEnv;
4
+ /**
5
+ * Returns the value of a required environment variable.
6
+ * Throws if the variable is missing or empty — call at service startup
7
+ * (after dotenv.config()) so misconfigured services fail fast instead of
8
+ * running with insecure defaults.
9
+ */
10
+ function requireEnv(name) {
11
+ const value = process.env[name];
12
+ if (!value) {
13
+ throw new Error(`Missing required environment variable: ${name}`);
14
+ }
15
+ return value;
16
+ }
17
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/config/env.ts"],"names":[],"mappings":";;AAMA,gCAMC;AAZD;;;;;GAKG;AACH,SAAgB,UAAU,CAAC,IAAY;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,0CAA0C,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const connectDB: (serviceName?: string, uri?: string) => Promise<void>;
2
+ export declare const disconnectDB: (serviceName?: string) => Promise<void>;
3
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/database/connection.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,SAAS,GAAU,cAAc,MAAM,EAAE,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CA6BhF,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,cAAc,MAAM,KAAG,OAAO,CAAC,IAAI,CASrE,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.disconnectDB = exports.connectDB = void 0;
7
+ const mongoose_1 = __importDefault(require("mongoose"));
8
+ const logger_1 = __importDefault(require("../logging/logger"));
9
+ let connected = false;
10
+ const connectDB = async (serviceName, uri) => {
11
+ if (connected)
12
+ return;
13
+ const mongoUri = uri || process.env.MONGODB_URI;
14
+ if (!mongoUri) {
15
+ throw new Error('MONGODB_URI environment variable is not set');
16
+ }
17
+ try {
18
+ await mongoose_1.default.connect(mongoUri);
19
+ connected = true;
20
+ logger_1.default.info('MongoDB connected', { service: serviceName });
21
+ mongoose_1.default.connection.on('error', (err) => {
22
+ logger_1.default.error('MongoDB connection error', { service: serviceName, error: err.message });
23
+ });
24
+ mongoose_1.default.connection.on('disconnected', () => {
25
+ logger_1.default.warn('MongoDB disconnected', { service: serviceName });
26
+ });
27
+ mongoose_1.default.connection.on('reconnected', () => {
28
+ logger_1.default.info('MongoDB reconnected', { service: serviceName });
29
+ });
30
+ }
31
+ catch (error) {
32
+ logger_1.default.error('Failed to connect to MongoDB', { service: serviceName, error: error.message });
33
+ throw error;
34
+ }
35
+ };
36
+ exports.connectDB = connectDB;
37
+ const disconnectDB = async (serviceName) => {
38
+ try {
39
+ await mongoose_1.default.connection.close();
40
+ connected = false;
41
+ logger_1.default.info('MongoDB connection closed', { service: serviceName });
42
+ }
43
+ catch (error) {
44
+ logger_1.default.error('Error closing MongoDB connection', { service: serviceName, error: error.message });
45
+ throw error;
46
+ }
47
+ };
48
+ exports.disconnectDB = disconnectDB;
49
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/database/connection.ts"],"names":[],"mappings":";;;;;;AAAA,wDAAgC;AAChC,+DAAuC;AAEvC,IAAI,SAAS,GAAG,KAAK,CAAC;AAEf,MAAM,SAAS,GAAG,KAAK,EAAE,WAAoB,EAAE,GAAY,EAAiB,EAAE;IACnF,IAAI,SAAS;QAAE,OAAO;IAEtB,MAAM,QAAQ,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,kBAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,SAAS,GAAG,IAAI,CAAC;QAEjB,gBAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAE3D,kBAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YAC7C,gBAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACzF,CAAC,CAAC,CAAC;QAEH,kBAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;YAC1C,gBAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,kBAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;YACzC,gBAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,gBAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACxG,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AA7BW,QAAA,SAAS,aA6BpB;AAEK,MAAM,YAAY,GAAG,KAAK,EAAE,WAAoB,EAAiB,EAAE;IACxE,IAAI,CAAC;QACH,MAAM,kBAAQ,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAClC,SAAS,GAAG,KAAK,CAAC;QAClB,gBAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,gBAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5G,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AATW,QAAA,YAAY,gBASvB"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Base class for errors that should be turned into a specific HTTP response
3
+ * by the shared errorHandler, instead of every controller hand-rolling
4
+ * try/catch + string-matching on error.message to pick a status code.
5
+ *
6
+ * Express 5 forwards rejected promises from async route handlers to the
7
+ * mounted error handler automatically, so controllers can just
8
+ * `throw new NotFoundError(...)` and stop wrapping in try/catch.
9
+ */
10
+ export declare class HttpError extends Error {
11
+ statusCode: number;
12
+ constructor(statusCode: number, message: string);
13
+ }
14
+ export declare class BadRequestError extends HttpError {
15
+ constructor(message?: string);
16
+ }
17
+ export declare class UnauthorizedError extends HttpError {
18
+ constructor(message?: string);
19
+ }
20
+ export declare class ForbiddenError extends HttpError {
21
+ constructor(message?: string);
22
+ }
23
+ export declare class NotFoundError extends HttpError {
24
+ constructor(message?: string);
25
+ }
26
+ export declare class ConflictError extends HttpError {
27
+ constructor(message?: string);
28
+ }
29
+ export declare class TooManyRequestsError extends HttpError {
30
+ constructor(message?: string);
31
+ }
32
+ //# sourceMappingURL=HttpError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpError.d.ts","sourceRoot":"","sources":["../../src/errors/HttpError.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,UAAU,EAAE,MAAM,CAAC;gBAEP,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAQhD;AAED,qBAAa,eAAgB,SAAQ,SAAS;gBAChC,OAAO,SAAgB;CAGpC;AAED,qBAAa,iBAAkB,SAAQ,SAAS;gBAClC,OAAO,SAAiB;CAGrC;AAED,qBAAa,cAAe,SAAQ,SAAS;gBAC/B,OAAO,SAAkB;CAGtC;AAED,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,OAAO,SAAc;CAGlC;AAED,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,OAAO,SAAa;CAGjC;AAED,qBAAa,oBAAqB,SAAQ,SAAS;gBACrC,OAAO,SAAsB;CAG1C"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TooManyRequestsError = exports.ConflictError = exports.NotFoundError = exports.ForbiddenError = exports.UnauthorizedError = exports.BadRequestError = exports.HttpError = void 0;
4
+ /**
5
+ * Base class for errors that should be turned into a specific HTTP response
6
+ * by the shared errorHandler, instead of every controller hand-rolling
7
+ * try/catch + string-matching on error.message to pick a status code.
8
+ *
9
+ * Express 5 forwards rejected promises from async route handlers to the
10
+ * mounted error handler automatically, so controllers can just
11
+ * `throw new NotFoundError(...)` and stop wrapping in try/catch.
12
+ */
13
+ class HttpError extends Error {
14
+ statusCode;
15
+ constructor(statusCode, message) {
16
+ super(message);
17
+ this.name = new.target.name;
18
+ this.statusCode = statusCode;
19
+ // Restore the prototype chain (needed when compiling to ES2018 targets
20
+ // where `extends Error` doesn't preserve instanceof checks correctly).
21
+ Object.setPrototypeOf(this, new.target.prototype);
22
+ }
23
+ }
24
+ exports.HttpError = HttpError;
25
+ class BadRequestError extends HttpError {
26
+ constructor(message = 'Bad request') {
27
+ super(400, message);
28
+ }
29
+ }
30
+ exports.BadRequestError = BadRequestError;
31
+ class UnauthorizedError extends HttpError {
32
+ constructor(message = 'Unauthorized') {
33
+ super(401, message);
34
+ }
35
+ }
36
+ exports.UnauthorizedError = UnauthorizedError;
37
+ class ForbiddenError extends HttpError {
38
+ constructor(message = 'Access denied') {
39
+ super(403, message);
40
+ }
41
+ }
42
+ exports.ForbiddenError = ForbiddenError;
43
+ class NotFoundError extends HttpError {
44
+ constructor(message = 'Not found') {
45
+ super(404, message);
46
+ }
47
+ }
48
+ exports.NotFoundError = NotFoundError;
49
+ class ConflictError extends HttpError {
50
+ constructor(message = 'Conflict') {
51
+ super(409, message);
52
+ }
53
+ }
54
+ exports.ConflictError = ConflictError;
55
+ class TooManyRequestsError extends HttpError {
56
+ constructor(message = 'Too many requests') {
57
+ super(429, message);
58
+ }
59
+ }
60
+ exports.TooManyRequestsError = TooManyRequestsError;
61
+ //# sourceMappingURL=HttpError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../src/errors/HttpError.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;GAQG;AACH,MAAa,SAAU,SAAQ,KAAK;IAClC,UAAU,CAAS;IAEnB,YAAY,UAAkB,EAAE,OAAe;QAC7C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,uEAAuE;QACvE,uEAAuE;QACvE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAXD,8BAWC;AAED,MAAa,eAAgB,SAAQ,SAAS;IAC5C,YAAY,OAAO,GAAG,aAAa;QACjC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtB,CAAC;CACF;AAJD,0CAIC;AAED,MAAa,iBAAkB,SAAQ,SAAS;IAC9C,YAAY,OAAO,GAAG,cAAc;QAClC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtB,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,cAAe,SAAQ,SAAS;IAC3C,YAAY,OAAO,GAAG,eAAe;QACnC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtB,CAAC;CACF;AAJD,wCAIC;AAED,MAAa,aAAc,SAAQ,SAAS;IAC1C,YAAY,OAAO,GAAG,WAAW;QAC/B,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtB,CAAC;CACF;AAJD,sCAIC;AAED,MAAa,aAAc,SAAQ,SAAS;IAC1C,YAAY,OAAO,GAAG,UAAU;QAC9B,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtB,CAAC;CACF;AAJD,sCAIC;AAED,MAAa,oBAAqB,SAAQ,SAAS;IACjD,YAAY,OAAO,GAAG,mBAAmB;QACvC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtB,CAAC;CACF;AAJD,oDAIC"}
@@ -0,0 +1,21 @@
1
+ import { Request, Response } from 'express';
2
+ import { metricsHandler } from '../metrics';
3
+ /**
4
+ * Health check endpoint with database connectivity
5
+ * Returns comprehensive health status for monitoring
6
+ */
7
+ export declare const healthCheck: (req: Request, res: Response) => Promise<void>;
8
+ /**
9
+ * Liveness check: confirms the process is up and serving HTTP, without
10
+ * touching MongoDB or any other dependency. Used by the Docker-level
11
+ * HEALTHCHECK so a transient DB outage doesn't get reported as the
12
+ * container itself being unhealthy — `/health` (above) is the DB-aware
13
+ * readiness check for dashboards/monitoring.
14
+ */
15
+ export declare const healthLive: (req: Request, res: Response) => void;
16
+ /**
17
+ * Prometheus metrics endpoint
18
+ * Exposes application metrics for monitoring
19
+ */
20
+ export { metricsHandler };
21
+ //# sourceMappingURL=healthController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healthController.d.ts","sourceRoot":"","sources":["../../src/health/healthController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAU,KAAK,OAAO,EAAE,KAAK,QAAQ,kBA8B5D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,SAErD,CAAC;AAEF;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,56 @@
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.metricsHandler = exports.healthLive = exports.healthCheck = void 0;
7
+ const mongoose_1 = __importDefault(require("mongoose"));
8
+ const metrics_1 = require("../metrics");
9
+ Object.defineProperty(exports, "metricsHandler", { enumerable: true, get: function () { return metrics_1.metricsHandler; } });
10
+ /**
11
+ * Health check endpoint with database connectivity
12
+ * Returns comprehensive health status for monitoring
13
+ */
14
+ const healthCheck = async (req, res) => {
15
+ try {
16
+ // Check MongoDB connection
17
+ const mongoState = mongoose_1.default.connection.readyState;
18
+ const isMongoHealthy = mongoState === 1; // 1 = connected
19
+ const healthResponse = {
20
+ status: isMongoHealthy ? 'ok' : 'error',
21
+ service: process.env.SERVICE_NAME || 'unknown-service',
22
+ type: 'backend',
23
+ timestamp: new Date().toISOString(),
24
+ version: process.env.npm_package_version || '1.0.0',
25
+ description: process.env.SERVICE_DESCRIPTION || 'Backend service',
26
+ dependencies: {
27
+ mongodb: isMongoHealthy ? 'connected' : 'disconnected'
28
+ }
29
+ };
30
+ res.status(isMongoHealthy ? 200 : 503).json(healthResponse);
31
+ }
32
+ catch (error) {
33
+ res.status(503).json({
34
+ status: 'error',
35
+ service: process.env.SERVICE_NAME || 'unknown-service',
36
+ type: 'backend',
37
+ timestamp: new Date().toISOString(),
38
+ version: process.env.npm_package_version || '1.0.0',
39
+ description: process.env.SERVICE_DESCRIPTION || 'Backend service',
40
+ error: 'Health check failed'
41
+ });
42
+ }
43
+ };
44
+ exports.healthCheck = healthCheck;
45
+ /**
46
+ * Liveness check: confirms the process is up and serving HTTP, without
47
+ * touching MongoDB or any other dependency. Used by the Docker-level
48
+ * HEALTHCHECK so a transient DB outage doesn't get reported as the
49
+ * container itself being unhealthy — `/health` (above) is the DB-aware
50
+ * readiness check for dashboards/monitoring.
51
+ */
52
+ const healthLive = (req, res) => {
53
+ res.status(200).json({ status: 'ok' });
54
+ };
55
+ exports.healthLive = healthLive;
56
+ //# sourceMappingURL=healthController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healthController.js","sourceRoot":"","sources":["../../src/health/healthController.ts"],"names":[],"mappings":";;;;;;AACA,wDAAgC;AAChC,wCAA4C;AAqDnC,+FArDA,wBAAc,OAqDA;AAnDvB;;;GAGG;AACI,MAAM,WAAW,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC/D,IAAI,CAAC;QACH,2BAA2B;QAC3B,MAAM,UAAU,GAAG,kBAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;QAClD,MAAM,cAAc,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,gBAAgB;QAEzD,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;YACvC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,iBAAiB;YACtD,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO;YACnD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,iBAAiB;YACjE,YAAY,EAAE;gBACZ,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;aACvD;SACF,CAAC;QAEF,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,MAAM,EAAE,OAAO;YACf,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,iBAAiB;YACtD,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO;YACnD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,iBAAiB;YACjE,KAAK,EAAE,qBAAqB;SAC7B,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;AA9BW,QAAA,WAAW,eA8BtB;AAEF;;;;;;GAMG;AACI,MAAM,UAAU,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACxD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC,CAAC;AAFW,QAAA,UAAU,cAErB"}
@@ -0,0 +1,20 @@
1
+ export { createBaseApp } from './app/createBaseApp';
2
+ export type { CreateBaseAppOptions } from './app/createBaseApp';
3
+ export { default as logger } from './logging/logger';
4
+ export { healthCheck, healthLive, metricsHandler } from './health/healthController';
5
+ export { connectDB, disconnectDB } from './database/connection';
6
+ export { requireEnv } from './config/env';
7
+ export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, TooManyRequestsError } from './errors/HttpError';
8
+ export { authenticateToken } from './middleware/authMiddleware';
9
+ export { createCorsMiddleware } from './middleware/corsMiddleware';
10
+ export { errorHandler } from './middleware/errorHandler';
11
+ export { requestLogger, requestLoggerWithMetrics, simpleRequestLogger } from './middleware/requestLogger';
12
+ export { securityHeaders, createRateLimiter, standardRateLimiter, strictRateLimiter } from './middleware/security';
13
+ export { validate } from './middleware/validate';
14
+ export type { UserPayload } from './types/auth';
15
+ export { generateCorrelationId, correlationMiddleware } from './utils/correlation';
16
+ export { createApiResponse, sendSuccess, sendError } from './utils/response';
17
+ export type { ApiResponse } from './utils/response';
18
+ export { metricsMiddleware, httpRequestDuration, httpRequestsTotal, databaseQueryDuration, databaseQueriesTotal, businessMetrics, register } from './metrics';
19
+ export { initTracer, getTracer, startSpan, tracingMiddleware, createChildSpan, logToSpan, setSpanTag, injectHeaders, extractSpanContext } from './tracing';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGpF,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAGvJ,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACnH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACT,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,aAAa,EACb,kBAAkB,EACnB,MAAM,WAAW,CAAC"}