@groundbrick/express-adapter 0.0.1

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 (58) hide show
  1. package/README.md +449 -0
  2. package/dist/core/BaseController.d.ts +23 -0
  3. package/dist/core/BaseController.d.ts.map +1 -0
  4. package/dist/core/BaseController.js +50 -0
  5. package/dist/core/BaseController.js.map +1 -0
  6. package/dist/core/ExpressApp.d.ts +20 -0
  7. package/dist/core/ExpressApp.d.ts.map +1 -0
  8. package/dist/core/ExpressApp.js +183 -0
  9. package/dist/core/ExpressApp.js.map +1 -0
  10. package/dist/index.d.ts +9 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +11 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/middleware/ErrorHandler.d.ts +8 -0
  15. package/dist/middleware/ErrorHandler.d.ts.map +1 -0
  16. package/dist/middleware/ErrorHandler.js +64 -0
  17. package/dist/middleware/ErrorHandler.js.map +1 -0
  18. package/dist/middleware/JwtMiddleware.d.ts +17 -0
  19. package/dist/middleware/JwtMiddleware.d.ts.map +1 -0
  20. package/dist/middleware/JwtMiddleware.js +140 -0
  21. package/dist/middleware/JwtMiddleware.js.map +1 -0
  22. package/dist/middleware/RequestLogger.d.ts +8 -0
  23. package/dist/middleware/RequestLogger.d.ts.map +1 -0
  24. package/dist/middleware/RequestLogger.js +39 -0
  25. package/dist/middleware/RequestLogger.js.map +1 -0
  26. package/dist/middleware/ResponseFormatter.d.ts +5 -0
  27. package/dist/middleware/ResponseFormatter.d.ts.map +1 -0
  28. package/dist/middleware/ResponseFormatter.js +39 -0
  29. package/dist/middleware/ResponseFormatter.js.map +1 -0
  30. package/dist/types/ApiResponse.d.ts +17 -0
  31. package/dist/types/ApiResponse.d.ts.map +1 -0
  32. package/dist/types/ApiResponse.js +2 -0
  33. package/dist/types/ApiResponse.js.map +1 -0
  34. package/dist/types/Auth.d.ts +21 -0
  35. package/dist/types/Auth.d.ts.map +1 -0
  36. package/dist/types/Auth.js +2 -0
  37. package/dist/types/Auth.js.map +1 -0
  38. package/dist/types/Controller.d.ts +23 -0
  39. package/dist/types/Controller.d.ts.map +1 -0
  40. package/dist/types/Controller.js +2 -0
  41. package/dist/types/Controller.js.map +1 -0
  42. package/dist/types/ExpressConfig.d.ts +35 -0
  43. package/dist/types/ExpressConfig.d.ts.map +1 -0
  44. package/dist/types/ExpressConfig.js +2 -0
  45. package/dist/types/ExpressConfig.js.map +1 -0
  46. package/dist/types/RouteHandler.d.ts +9 -0
  47. package/dist/types/RouteHandler.d.ts.map +1 -0
  48. package/dist/types/RouteHandler.js +2 -0
  49. package/dist/types/RouteHandler.js.map +1 -0
  50. package/dist/types/index.d.ts +56 -0
  51. package/dist/types/index.d.ts.map +1 -0
  52. package/dist/types/index.js +2 -0
  53. package/dist/types/index.js.map +1 -0
  54. package/dist/utils/index.d.ts +53 -0
  55. package/dist/utils/index.d.ts.map +1 -0
  56. package/dist/utils/index.js +263 -0
  57. package/dist/utils/index.js.map +1 -0
  58. package/package.json +81 -0
@@ -0,0 +1,183 @@
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import helmet from 'helmet';
4
+ import cookieParser from 'cookie-parser';
5
+ // import rateLimit, { RateLimitRequestHandler } from 'express-rate-limit';
6
+ import { createLogger } from '@groundbrick/logger';
7
+ import { ErrorHandler } from '../middleware/ErrorHandler.js';
8
+ import { RequestLogger } from '../middleware/RequestLogger.js';
9
+ import { ResponseFormatter } from '../middleware/ResponseFormatter.js';
10
+ export class ExpressApp {
11
+ app;
12
+ logger;
13
+ config;
14
+ errorHandler;
15
+ requestLogger;
16
+ constructor(config = {}) {
17
+ this.config = {
18
+ port: 3000,
19
+ host: '0.0.0.0',
20
+ cors: {
21
+ origin: true,
22
+ credentials: true
23
+ },
24
+ security: {
25
+ helmet: true,
26
+ // rateLimit: {
27
+ // windowMs: 15 * 60 * 1000, // 15 minutes
28
+ // max: 100 // limit each IP to 100 requests per windowMs
29
+ // }
30
+ },
31
+ compression: true,
32
+ bodyParser: {
33
+ json: { limit: '10mb' },
34
+ urlencoded: { limit: '10mb', extended: true }
35
+ },
36
+ trustProxy: false,
37
+ ...config
38
+ };
39
+ this.logger = createLogger({
40
+ context: 'express-app',
41
+ ...this.config.logger
42
+ });
43
+ this.app = express();
44
+ this.errorHandler = new ErrorHandler(this.logger);
45
+ this.requestLogger = new RequestLogger(this.logger);
46
+ this.setupMiddleware();
47
+ this.setupRoutes();
48
+ }
49
+ setupMiddleware() {
50
+ // Trust proxy if configured
51
+ if (this.config.trustProxy) {
52
+ this.app.set('trust proxy', this.config.trustProxy);
53
+ }
54
+ // Security middleware
55
+ if (this.config.security?.helmet) {
56
+ this.app.use(helmet());
57
+ }
58
+ // // Rate limiting
59
+ // if (this.config.security?.rateLimit) {
60
+ // const limiter: RateLimitRequestHandler = rateLimit({
61
+ // windowMs: this.config.security.rateLimit.windowMs,
62
+ // max: this.config.security.rateLimit.max,
63
+ // message: this.config.security.rateLimit.message || 'Too many requests'
64
+ // });
65
+ // this.app.use((limiter as express.RequestHandler));
66
+ // }
67
+ // CORS
68
+ if (this.config.cors) {
69
+ this.app.use(cors(this.config.cors));
70
+ }
71
+ // Cookie parser - REQUIRED for HttpOnly cookies
72
+ this.app.use(cookieParser());
73
+ // // Compression
74
+ // if (this.config.compression) {
75
+ // this.app.use(compression({ level: 6 }));
76
+ // }
77
+ // Body parsing - skip multipart requests to avoid conflicts with multer
78
+ this.app.use((req, res, next) => {
79
+ if (req.headers['content-type']?.startsWith('multipart/form-data')) {
80
+ return next();
81
+ }
82
+ express.json(this.config.bodyParser?.json)(req, res, next);
83
+ });
84
+ this.app.use((req, res, next) => {
85
+ if (req.headers['content-type']?.startsWith('multipart/form-data')) {
86
+ return next();
87
+ }
88
+ express.urlencoded(this.config.bodyParser?.urlencoded)(req, res, next);
89
+ });
90
+ // Request logging
91
+ this.app.use(this.requestLogger.log);
92
+ // Response formatting
93
+ this.app.use(ResponseFormatter.format);
94
+ // Static file serving
95
+ if (this.config.static) {
96
+ this.setupStaticFiles();
97
+ }
98
+ }
99
+ setupStaticFiles() {
100
+ if (this.config.static) {
101
+ Object.entries(this.config.static).forEach(([path, directory]) => {
102
+ this.app.use(path, express.static(directory));
103
+ this.logger.info(`Serving static files from '${directory}' at '${path}'`);
104
+ });
105
+ }
106
+ }
107
+ setupRoutes() {
108
+ // Health check endpoint
109
+ this.app.get('/health', (_req, res) => {
110
+ res.json({
111
+ status: 'healthy',
112
+ timestamp: new Date().toISOString(),
113
+ uptime: process.uptime()
114
+ });
115
+ });
116
+ // Root endpoint
117
+ this.app.get('/', (_req, res) => {
118
+ res.json({
119
+ message: '200systems Microframework Express API',
120
+ version: '1.0.0',
121
+ timestamp: new Date().toISOString()
122
+ });
123
+ });
124
+ }
125
+ addRoutes(routes) {
126
+ routes.forEach(route => {
127
+ const middlewares = route.middleware || [];
128
+ this.app[route.method](route.path, ...middlewares, route.handler);
129
+ this.logger.info(`Registered route: ${route.method.toUpperCase()} ${route.path}`);
130
+ });
131
+ }
132
+ addRoute(route) {
133
+ this.addRoutes([route]);
134
+ }
135
+ getApp() {
136
+ return this.app;
137
+ }
138
+ setupErrorHandling() {
139
+ // 404 handler - must be after all routes
140
+ this.app.use('*', (req, res) => {
141
+ res.status(404).json({
142
+ success: false,
143
+ error: {
144
+ message: 'Route not found',
145
+ code: 'NOT_FOUND'
146
+ },
147
+ meta: {
148
+ timestamp: new Date().toISOString(),
149
+ requestId: req.headers['x-request-id']
150
+ }
151
+ });
152
+ });
153
+ // Global error handler - must be last
154
+ this.app.use(this.errorHandler.handle);
155
+ }
156
+ start() {
157
+ return new Promise((resolve) => {
158
+ this.setupErrorHandling();
159
+ const port = this.config.port ?? 3000;
160
+ const host = this.config.host ?? '0.0.0.0';
161
+ const server = this.app.listen(port, host, () => {
162
+ this.logger.info(`Server started on ${host}:${port}`);
163
+ resolve();
164
+ });
165
+ // Graceful shutdown
166
+ process.on('SIGTERM', () => {
167
+ this.logger.info('SIGTERM received, shutting down gracefully');
168
+ server.close(() => {
169
+ this.logger.info('Server closed');
170
+ process.exit(0);
171
+ });
172
+ });
173
+ process.on('SIGINT', () => {
174
+ this.logger.info('SIGINT received, shutting down gracefully');
175
+ server.close(() => {
176
+ this.logger.info('Server closed');
177
+ process.exit(0);
178
+ });
179
+ });
180
+ });
181
+ }
182
+ }
183
+ //# sourceMappingURL=ExpressApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressApp.js","sourceRoot":"","sources":["../../src/core/ExpressApp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { ExpressApp } from './core/ExpressApp.js';
2
+ export { BaseController } from './core/BaseController.js';
3
+ export { ErrorHandler } from './middleware/ErrorHandler.js';
4
+ export { RequestLogger } from './middleware/RequestLogger.js';
5
+ export { ResponseFormatter } from './middleware/ResponseFormatter.js';
6
+ export { JwtMiddleware } from './middleware/JwtMiddleware.js';
7
+ export type * from './types/index.js';
8
+ export { ResponseHelper, ValidationHelper, PaginationHelper, RequestHelper, SecurityHelper } from './utils/index.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG9D,mBAAmB,kBAAkB,CAAC;AAGtC,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACf,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ // Core classes
2
+ export { ExpressApp } from './core/ExpressApp.js';
3
+ export { BaseController } from './core/BaseController.js';
4
+ // Middleware
5
+ export { ErrorHandler } from './middleware/ErrorHandler.js';
6
+ export { RequestLogger } from './middleware/RequestLogger.js';
7
+ export { ResponseFormatter } from './middleware/ResponseFormatter.js';
8
+ export { JwtMiddleware } from './middleware/JwtMiddleware.js';
9
+ // Utility helpers
10
+ export { ResponseHelper, ValidationHelper, PaginationHelper, RequestHelper, SecurityHelper } from './utils/index.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,eAAe;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,aAAa;AACb,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAK9D,kBAAkB;AAClB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACf,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import { Logger } from '@groundbrick/logger';
3
+ export declare class ErrorHandler {
4
+ private logger;
5
+ constructor(logger: Logger);
6
+ handle: (error: Error, req: Request, res: Response, _next: NextFunction) => void;
7
+ }
8
+ //# 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,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAI7C,qBAAa,YAAY;IACT,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC,MAAM,GAAI,OAAO,KAAK,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,OAAO,YAAY,KAAG,IAAI,CA0D7E;CACL"}
@@ -0,0 +1,64 @@
1
+ import { BusinessError } from '@groundbrick/service-base';
2
+ export class ErrorHandler {
3
+ logger;
4
+ constructor(logger) {
5
+ this.logger = logger;
6
+ }
7
+ handle = (error, req, res, _next) => {
8
+ const requestId = req.headers['x-request-id'] || 'unknown';
9
+ this.logger.error('Request error', error, {
10
+ error: error.message,
11
+ stack: error.stack,
12
+ path: req.path,
13
+ method: req.method,
14
+ requestId,
15
+ body: req.body,
16
+ query: req.query,
17
+ params: req.params
18
+ });
19
+ let statusCode = 500;
20
+ let errorMessage = 'Internal server error';
21
+ let errorCode = 'INTERNAL_ERROR';
22
+ let details = undefined;
23
+ // Handle BusinessError (includes validation errors)
24
+ if (BusinessError.isBusinessError(error)) {
25
+ statusCode = 400;
26
+ errorMessage = error.message;
27
+ errorCode = error.code;
28
+ details = error.context;
29
+ // Check if it's a validation error specifically
30
+ if (error.code === 'VALIDATION_FAILED' || error.code === 'VALIDATION_ERROR') {
31
+ errorCode = 'VALIDATION_ERROR';
32
+ }
33
+ }
34
+ else if (error.name === 'UnauthorizedError') {
35
+ statusCode = 401;
36
+ errorMessage = 'Unauthorized';
37
+ errorCode = 'UNAUTHORIZED';
38
+ }
39
+ else if (error.name === 'ForbiddenError') {
40
+ statusCode = 403;
41
+ errorMessage = 'Forbidden';
42
+ errorCode = 'FORBIDDEN';
43
+ }
44
+ else if (error.name === 'NotFoundError') {
45
+ statusCode = 404;
46
+ errorMessage = 'Resource not found';
47
+ errorCode = 'NOT_FOUND';
48
+ }
49
+ const response = {
50
+ success: false,
51
+ error: {
52
+ message: errorMessage,
53
+ code: errorCode,
54
+ ...(details && { details })
55
+ },
56
+ meta: {
57
+ timestamp: new Date().toISOString(),
58
+ requestId
59
+ }
60
+ };
61
+ res.status(statusCode).json(response);
62
+ };
63
+ }
64
+ //# sourceMappingURL=ErrorHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorHandler.js","sourceRoot":"","sources":["../../src/middleware/ErrorHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG1D,MAAM,OAAO,YAAY;IACD;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAI,CAAC;IAEvC,MAAM,GAAG,CAAC,KAAY,EAAE,GAAY,EAAE,GAAa,EAAE,KAAmB,EAAQ,EAAE;QAC9E,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAW,IAAI,SAAS,CAAC;QAErE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,KAAc,EAAE;YAC/C,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,SAAS;YACT,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,GAAG,CAAC,MAAM;SACrB,CAAC,CAAC;QAEH,IAAI,UAAU,GAAG,GAAG,CAAC;QACrB,IAAI,YAAY,GAAG,uBAAuB,CAAC;QAC3C,IAAI,SAAS,GAAG,gBAAgB,CAAC;QACjC,IAAI,OAAO,GAAQ,SAAS,CAAC;QAE7B,oDAAoD;QACpD,IAAI,aAAa,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,UAAU,GAAG,GAAG,CAAC;YACjB,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;YAC7B,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC;YACvB,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;YAExB,gDAAgD;YAChD,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBAC1E,SAAS,GAAG,kBAAkB,CAAC;YACnC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YAC5C,UAAU,GAAG,GAAG,CAAC;YACjB,YAAY,GAAG,cAAc,CAAC;YAC9B,SAAS,GAAG,cAAc,CAAC;QAC/B,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACzC,UAAU,GAAG,GAAG,CAAC;YACjB,YAAY,GAAG,WAAW,CAAC;YAC3B,SAAS,GAAG,WAAW,CAAC;QAC5B,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACxC,UAAU,GAAG,GAAG,CAAC;YACjB,YAAY,GAAG,oBAAoB,CAAC;YACpC,SAAS,GAAG,WAAW,CAAC;QAC5B,CAAC;QAED,MAAM,QAAQ,GAAgB;YAC1B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE;gBACH,OAAO,EAAE,YAAY;gBACrB,IAAI,EAAE,SAAS;gBACf,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;aAC9B;YACD,IAAI,EAAE;gBACF,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,SAAS;aACZ;SACJ,CAAC;QAEF,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC,CAAC;CACL"}
@@ -0,0 +1,17 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import { StringValue } from 'ms';
3
+ import { Logger } from '@groundbrick/logger';
4
+ import { JwtMiddlewareConfig, JwtPayload } from '../types/Auth.js';
5
+ export declare class JwtMiddleware {
6
+ private config;
7
+ private logger;
8
+ constructor(config: JwtMiddlewareConfig, logger: Logger);
9
+ private shouldSkipPath;
10
+ private extractToken;
11
+ authenticate: (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
12
+ optional: (req: Request, _res: Response, next: NextFunction) => void;
13
+ requireRole: (requiredRoles: string | string[]) => (req: Request, res: Response, next: NextFunction) => void;
14
+ static generateToken(payload: JwtPayload, secret: string, expiresIn?: StringValue): string;
15
+ static decodeToken(token: string): JwtPayload | null;
16
+ }
17
+ //# sourceMappingURL=JwtMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JwtMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/JwtMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAwB,MAAM,kBAAkB,CAAC;AAGzF,qBAAa,aAAa;IACtB,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM;IAcvD,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,YAAY;IAapB,YAAY,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,+CAoD7D;IAEF,QAAQ,GAAI,KAAK,OAAO,EAAE,MAAM,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAwBjE;IAEF,WAAW,GAAI,eAAe,MAAM,GAAG,MAAM,EAAE,MAGnC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAwBhE;IAEF,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAE,WAAmB,GAAG,MAAM;IAKjG,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;CAOvD"}
@@ -0,0 +1,140 @@
1
+ import jwt from 'jsonwebtoken';
2
+ import { ResponseHelper } from '../utils/index.js';
3
+ export class JwtMiddleware {
4
+ config;
5
+ logger;
6
+ constructor(config, logger) {
7
+ this.config = {
8
+ secret: process.env.JWT_SECRET || 'default-secret',
9
+ algorithms: ['HS256'],
10
+ skipPaths: ['/health', '/'],
11
+ cookieName: 'token',
12
+ headerName: 'authorization',
13
+ onTokenExpired: (_req, res) => ResponseHelper.unauthorized(res, 'Token has expired'),
14
+ onTokenInvalid: (_req, res) => ResponseHelper.unauthorized(res, 'Invalid token'),
15
+ ...config
16
+ };
17
+ this.logger = logger;
18
+ }
19
+ shouldSkipPath(path) {
20
+ return this.config.skipPaths.some(skipPath => {
21
+ if (skipPath.endsWith('*')) {
22
+ return path.startsWith(skipPath.slice(0, -1));
23
+ }
24
+ return path === skipPath;
25
+ });
26
+ }
27
+ extractToken(req) {
28
+ const authHeader = req.headers[this.config.headerName];
29
+ if (authHeader) {
30
+ if (authHeader.startsWith('Bearer ')) {
31
+ return authHeader.substring(7);
32
+ }
33
+ return authHeader;
34
+ }
35
+ const token = req.cookies?.[this.config.cookieName];
36
+ return token || null;
37
+ }
38
+ authenticate = (req, res, next) => {
39
+ try {
40
+ if (this.shouldSkipPath(req.path)) {
41
+ return next();
42
+ }
43
+ const token = this.extractToken(req);
44
+ if (!token) {
45
+ this.logger.warn('No token provided', {
46
+ path: req.path,
47
+ method: req.method,
48
+ ip: req.ip
49
+ });
50
+ return ResponseHelper.unauthorized(res, 'No token provided');
51
+ }
52
+ const decoded = jwt.verify(token, this.config.secret, {
53
+ algorithms: this.config.algorithms
54
+ });
55
+ const authReq = req;
56
+ authReq.user = decoded;
57
+ authReq.token = token;
58
+ this.logger.debug('JWT authentication successful', {
59
+ userId: decoded.userId,
60
+ email: decoded.email,
61
+ path: req.path,
62
+ method: req.method
63
+ });
64
+ next();
65
+ }
66
+ catch (error) {
67
+ this.logger.warn('JWT authentication failed', {
68
+ error: error.message,
69
+ path: req.path,
70
+ method: req.method,
71
+ ip: req.ip
72
+ });
73
+ if (error instanceof jwt.TokenExpiredError) {
74
+ return this.config.onTokenExpired(req, res);
75
+ }
76
+ if (error instanceof jwt.JsonWebTokenError) {
77
+ return this.config.onTokenInvalid(req, res);
78
+ }
79
+ return ResponseHelper.unauthorized(res, 'Authentication failed');
80
+ }
81
+ };
82
+ optional = (req, _res, next) => {
83
+ try {
84
+ const token = this.extractToken(req);
85
+ if (!token) {
86
+ return next();
87
+ }
88
+ const decoded = jwt.verify(token, this.config.secret, {
89
+ algorithms: this.config.algorithms
90
+ });
91
+ const authReq = req;
92
+ authReq.user = decoded;
93
+ authReq.token = token;
94
+ next();
95
+ }
96
+ catch (error) {
97
+ this.logger.debug('Optional JWT authentication failed (continuing)', {
98
+ error: error.message,
99
+ path: req.path,
100
+ method: req.method
101
+ });
102
+ next();
103
+ }
104
+ };
105
+ requireRole = (requiredRoles) => {
106
+ const roles = Array.isArray(requiredRoles) ? requiredRoles : [requiredRoles];
107
+ return (req, res, next) => {
108
+ const authReq = req;
109
+ if (!authReq.user) {
110
+ throw ResponseHelper.unauthorized(res, 'Authentication required');
111
+ }
112
+ const userRoles = authReq.user.roles || [];
113
+ const hasRequiredRole = roles.some(role => userRoles.includes(role));
114
+ if (!hasRequiredRole) {
115
+ this.logger.warn('Insufficient permissions', {
116
+ userId: authReq.user.userId,
117
+ userRoles,
118
+ requiredRoles: roles,
119
+ path: req.path,
120
+ method: req.method
121
+ });
122
+ throw ResponseHelper.forbidden(res, 'Insufficient permissions');
123
+ }
124
+ next();
125
+ };
126
+ };
127
+ static generateToken(payload, secret, expiresIn = '24H') {
128
+ const options = { expiresIn };
129
+ return jwt.sign(payload, secret, options);
130
+ }
131
+ static decodeToken(token) {
132
+ try {
133
+ return jwt.decode(token);
134
+ }
135
+ catch {
136
+ return null;
137
+ }
138
+ }
139
+ }
140
+ //# sourceMappingURL=JwtMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JwtMiddleware.js","sourceRoot":"","sources":["../../src/middleware/JwtMiddleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import { Logger } from '@groundbrick/logger';
3
+ export declare class RequestLogger {
4
+ private logger;
5
+ constructor(logger: Logger);
6
+ log: (req: Request, res: Response, next: NextFunction) => void;
7
+ }
8
+ //# sourceMappingURL=RequestLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestLogger.d.ts","sourceRoot":"","sources":["../../src/middleware/RequestLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,qBAAa,aAAa;IACV,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC,GAAG,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAsC3D;CACL"}
@@ -0,0 +1,39 @@
1
+ export class RequestLogger {
2
+ logger;
3
+ constructor(logger) {
4
+ this.logger = logger;
5
+ }
6
+ log = (req, res, next) => {
7
+ const start = Date.now();
8
+ const requestId = req.headers['x-request-id'] ||
9
+ Math.random().toString(36).substring(2, 15);
10
+ // Add request ID to request for later use
11
+ req.headers['x-request-id'] = requestId;
12
+ // Log incoming request
13
+ this.logger.info('Incoming request', {
14
+ method: req.method,
15
+ path: req.path,
16
+ query: req.query,
17
+ userAgent: req.get('User-Agent'),
18
+ ip: req.ip,
19
+ requestId
20
+ });
21
+ // Override res.json to log response
22
+ const originalJson = res.json;
23
+ const logger = this.logger; // Capture logger reference
24
+ res.json = function (body) {
25
+ const duration = Date.now() - start;
26
+ // Log response
27
+ logger.info('Request completed', {
28
+ method: req.method,
29
+ path: req.path,
30
+ statusCode: res.statusCode,
31
+ duration,
32
+ requestId
33
+ });
34
+ return originalJson.call(this, body);
35
+ };
36
+ next();
37
+ };
38
+ }
39
+ //# sourceMappingURL=RequestLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestLogger.js","sourceRoot":"","sources":["../../src/middleware/RequestLogger.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,aAAa;IACF;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAI,CAAC;IAEvC,GAAG,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAW;YACnD,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEhD,0CAA0C;QAC1C,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;QAExC,uBAAuB;QACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE;YACjC,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;YAChC,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,SAAS;SACZ,CAAC,CAAC;QAEH,oCAAoC;QACpC,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,2BAA2B;QAEvD,GAAG,CAAC,IAAI,GAAG,UAAU,IAAS;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAEpC,eAAe;YACf,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE;gBAC7B,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,QAAQ;gBACR,SAAS;aACZ,CAAC,CAAC;YAEH,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC,CAAC;QAEF,IAAI,EAAE,CAAC;IACX,CAAC,CAAC;CACL"}
@@ -0,0 +1,5 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export declare class ResponseFormatter {
3
+ static format: (req: Request, res: Response, next: NextFunction) => void;
4
+ }
5
+ //# sourceMappingURL=ResponseFormatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseFormatter.d.ts","sourceRoot":"","sources":["../../src/middleware/ResponseFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI1D,qBAAa,iBAAiB;IAC1B,MAAM,CAAC,MAAM,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAyCrE;CACL"}
@@ -0,0 +1,39 @@
1
+ export class ResponseFormatter {
2
+ static format = (req, res, next) => {
3
+ const originalJson = res.json;
4
+ res.json = function (body) {
5
+ // If body is already a ServiceResult, format it
6
+ if (body && typeof body === 'object' && 'success' in body) {
7
+ const serviceResult = body;
8
+ const response = {
9
+ success: serviceResult.success,
10
+ ...(serviceResult.success && serviceResult.data !== undefined && { data: serviceResult.data }),
11
+ ...(serviceResult.error && {
12
+ error: {
13
+ message: serviceResult.error.message,
14
+ code: serviceResult.error.code,
15
+ ...(serviceResult.error.details && { details: serviceResult.error.details })
16
+ }
17
+ }),
18
+ meta: {
19
+ timestamp: new Date().toISOString(),
20
+ requestId: req.headers['x-request-id']
21
+ }
22
+ };
23
+ return originalJson.call(this, response);
24
+ }
25
+ // For other responses, wrap in standard format
26
+ const response = {
27
+ success: true,
28
+ data: body,
29
+ meta: {
30
+ timestamp: new Date().toISOString(),
31
+ requestId: req.headers['x-request-id']
32
+ }
33
+ };
34
+ return originalJson.call(this, response);
35
+ };
36
+ next();
37
+ };
38
+ }
39
+ //# sourceMappingURL=ResponseFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseFormatter.js","sourceRoot":"","sources":["../../src/middleware/ResponseFormatter.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,iBAAiB;IAC1B,MAAM,CAAC,MAAM,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QACtE,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC;QAE9B,GAAG,CAAC,IAAI,GAAG,UAAU,IAAS;YAC1B,gDAAgD;YAChD,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBACxD,MAAM,aAAa,GAAG,IAA0B,CAAC;gBAEjD,MAAM,QAAQ,GAAgB;oBAC1B,OAAO,EAAE,aAAa,CAAC,OAAO;oBAC9B,GAAG,CAAC,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC;oBAC9F,GAAG,CAAC,aAAa,CAAC,KAAK,IAAI;wBACvB,KAAK,EAAE;4BACH,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO;4BACpC,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI;4BAC9B,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;yBAC/E;qBACJ,CAAC;oBACF,IAAI,EAAE;wBACF,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;wBACnC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,CAAW;qBACnD;iBACJ,CAAC;gBAEF,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC7C,CAAC;YAED,+CAA+C;YAC/C,MAAM,QAAQ,GAAgB;gBAC1B,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE;oBACF,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,CAAW;iBACnD;aACJ,CAAC;YAEF,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC,CAAC;QAEF,IAAI,EAAE,CAAC;IACX,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface ApiResponse<T = any> {
2
+ success: boolean;
3
+ message?: string;
4
+ data?: T;
5
+ error?: {
6
+ message: string;
7
+ code?: string;
8
+ details?: any;
9
+ };
10
+ meta?: {
11
+ timestamp: string;
12
+ requestId?: string;
13
+ version?: string;
14
+ [key: string]: any;
15
+ };
16
+ }
17
+ //# sourceMappingURL=ApiResponse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiResponse.d.ts","sourceRoot":"","sources":["../../src/types/ApiResponse.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,GAAG,CAAC;KACjB,CAAC;IACF,IAAI,CAAC,EAAE;QACH,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACtB,CAAC;CACL"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ApiResponse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiResponse.js","sourceRoot":"","sources":["../../src/types/ApiResponse.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import type { Request, Response } from 'express';
2
+ export interface JwtMiddlewareConfig {
3
+ secret?: string;
4
+ algorithms?: string[];
5
+ skipPaths?: string[];
6
+ cookieName?: string;
7
+ headerName?: string;
8
+ onTokenExpired?: (req: Request, res: Response) => void;
9
+ onTokenInvalid?: (req: Request, res: Response) => void;
10
+ }
11
+ export interface JwtPayload {
12
+ userId: number;
13
+ email: string;
14
+ roles?: string[];
15
+ [key: string]: unknown;
16
+ }
17
+ export interface AuthenticatedRequest extends Request {
18
+ user?: JwtPayload;
19
+ token?: string;
20
+ }
21
+ //# sourceMappingURL=Auth.d.ts.map