@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.
- package/.versionrc.json +7 -0
- package/README.md +179 -0
- package/__mocks__/uuid.js +8 -0
- package/dist/app/createBaseApp.d.ts +44 -0
- package/dist/app/createBaseApp.d.ts.map +1 -0
- package/dist/app/createBaseApp.js +54 -0
- package/dist/app/createBaseApp.js.map +1 -0
- package/dist/config/env.d.ts +8 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +17 -0
- package/dist/config/env.js.map +1 -0
- package/dist/database/connection.d.ts +3 -0
- package/dist/database/connection.d.ts.map +1 -0
- package/dist/database/connection.js +49 -0
- package/dist/database/connection.js.map +1 -0
- package/dist/errors/HttpError.d.ts +32 -0
- package/dist/errors/HttpError.d.ts.map +1 -0
- package/dist/errors/HttpError.js +61 -0
- package/dist/errors/HttpError.js.map +1 -0
- package/dist/health/healthController.d.ts +21 -0
- package/dist/health/healthController.d.ts.map +1 -0
- package/dist/health/healthController.js +56 -0
- package/dist/health/healthController.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/logger.d.ts +4 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +78 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/metrics/index.d.ts +17 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +99 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/middleware/authMiddleware.d.ts +9 -0
- package/dist/middleware/authMiddleware.d.ts.map +1 -0
- package/dist/middleware/authMiddleware.js +32 -0
- package/dist/middleware/authMiddleware.js.map +1 -0
- package/dist/middleware/corsMiddleware.d.ts +20 -0
- package/dist/middleware/corsMiddleware.d.ts.map +1 -0
- package/dist/middleware/corsMiddleware.js +33 -0
- package/dist/middleware/corsMiddleware.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +14 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +88 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/requestLogger.d.ts +16 -0
- package/dist/middleware/requestLogger.d.ts.map +1 -0
- package/dist/middleware/requestLogger.js +49 -0
- package/dist/middleware/requestLogger.js.map +1 -0
- package/dist/middleware/security.d.ts +26 -0
- package/dist/middleware/security.d.ts.map +1 -0
- package/dist/middleware/security.js +47 -0
- package/dist/middleware/security.js.map +1 -0
- package/dist/middleware/validate.d.ts +11 -0
- package/dist/middleware/validate.d.ts.map +1 -0
- package/dist/middleware/validate.js +24 -0
- package/dist/middleware/validate.js.map +1 -0
- package/dist/tracing/index.d.ts +13 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +89 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/types/auth.d.ts +32 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +3 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/utils/correlation.d.ts +11 -0
- package/dist/utils/correlation.d.ts.map +1 -0
- package/dist/utils/correlation.js +23 -0
- package/dist/utils/correlation.js.map +1 -0
- package/dist/utils/response.d.ts +24 -0
- package/dist/utils/response.d.ts.map +1 -0
- package/dist/utils/response.js +35 -0
- package/dist/utils/response.js.map +1 -0
- package/jest.config.js +14 -0
- package/package.json +61 -0
- package/src/app/createBaseApp.test.ts +69 -0
- package/src/app/createBaseApp.ts +75 -0
- package/src/config/env.test.ts +28 -0
- package/src/config/env.ts +13 -0
- package/src/database/connection.test.ts +142 -0
- package/src/database/connection.ts +46 -0
- package/src/errors/HttpError.test.ts +38 -0
- package/src/errors/HttpError.ts +57 -0
- package/src/health/healthController.test.ts +91 -0
- package/src/health/healthController.ts +56 -0
- package/src/index.ts +60 -0
- package/src/logging/logger.test.ts +76 -0
- package/src/logging/logger.ts +103 -0
- package/src/metrics/index.test.ts +91 -0
- package/src/metrics/index.ts +110 -0
- package/src/middleware/authMiddleware.test.ts +104 -0
- package/src/middleware/authMiddleware.ts +29 -0
- package/src/middleware/corsMiddleware.test.ts +58 -0
- package/src/middleware/corsMiddleware.ts +36 -0
- package/src/middleware/errorHandler.test.ts +146 -0
- package/src/middleware/errorHandler.ts +98 -0
- package/src/middleware/requestLogger.test.ts +81 -0
- package/src/middleware/requestLogger.ts +47 -0
- package/src/middleware/security.test.ts +45 -0
- package/src/middleware/security.ts +43 -0
- package/src/middleware/validate.test.ts +60 -0
- package/src/middleware/validate.ts +23 -0
- package/src/tracing/index.test.ts +250 -0
- package/src/tracing/index.ts +97 -0
- package/src/types/auth.ts +33 -0
- package/src/utils/correlation.test.ts +47 -0
- package/src/utils/correlation.ts +22 -0
- package/src/utils/response.test.ts +64 -0
- package/src/utils/response.ts +60 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +20 -0
package/.versionrc.json
ADDED
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 @@
|
|
|
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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|