powr-sdk-api 1.2.2 → 1.3.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.
package/dist/index.js CHANGED
@@ -1,24 +1,24 @@
1
1
  "use strict";
2
2
 
3
- const errorMiddleware = require('./middleware/error');
4
- const responseMiddleware = require('./middleware/response');
5
- const requestMiddleware = require('./middleware/request');
6
- const createSwaggerSpec = require('./swagger');
7
- const logger = require('./services/logger');
8
3
  const {
9
- generateToken
10
- } = require('./utils/auth');
4
+ errorCatcher,
5
+ errorHandler
6
+ } = require("./middleware/error");
7
+ const {
8
+ requestHandler
9
+ } = require("./middleware/request");
11
10
  const {
12
- validateToken
13
- } = require('./middleware/auth');
11
+ validateAuth,
12
+ generateToken
13
+ } = require("./middleware/auth");
14
+ const createSwaggerSpec = require("./swagger");
15
+ const logger = require("./logger");
14
16
  module.exports = {
15
- errorCatcher: errorMiddleware.errorCatcher,
16
- errorHandler: errorMiddleware.errorHandler,
17
- requestLogger: requestMiddleware.requestLogger,
18
- responseFormatter: responseMiddleware.responseFormatter,
19
- responseLogger: responseMiddleware.responseLogger,
17
+ errorCatcher,
18
+ errorHandler,
19
+ requestHandler,
20
20
  logger,
21
21
  createSwaggerSpec,
22
22
  generateToken,
23
- validateToken
23
+ validateAuth
24
24
  };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ const winston = require('winston');
4
+ const {
5
+ S3Transport
6
+ } = require('./s3');
7
+
8
+ // Custom format for logs
9
+ const logFormat = winston.format.combine(winston.format.timestamp(), winston.format.errors({
10
+ stack: true
11
+ }), winston.format.json());
12
+
13
+ // Create base transports array with console transport
14
+ const transports = [new winston.transports.Console()];
15
+
16
+ // Add S3 transport only in production
17
+ if (process.env.NODE_ENV === 'production') {
18
+ transports.push(new S3Transport({
19
+ bucket: process.env.AWS_LOG_BUCKET_NAME,
20
+ prefix: 'logs',
21
+ bufferSize: 100,
22
+ flushInterval: 5000
23
+ }));
24
+ }
25
+
26
+ // Create the logger
27
+ const logger = winston.createLogger({
28
+ level: process.env.LOG_LEVEL || 'info',
29
+ format: logFormat,
30
+ defaultMeta: {
31
+ service: process.env.LOG_SERVICE_NAME
32
+ },
33
+ transports
34
+ });
35
+ module.exports = logger;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+
3
+ const winston = require('winston');
4
+ const {
5
+ S3Client,
6
+ PutObjectCommand
7
+ } = require('@aws-sdk/client-s3');
8
+
9
+ // Create S3 client
10
+ const s3Client = new S3Client({
11
+ region: process.env.AWS_REGION,
12
+ credentials: {
13
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
14
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
15
+ }
16
+ });
17
+
18
+ /**
19
+ * Custom Winston transport for logging to S3
20
+ */
21
+ class S3Transport extends winston.Transport {
22
+ constructor(opts) {
23
+ super(opts);
24
+ this.bucket = opts.bucket;
25
+ this.prefix = opts.prefix || '';
26
+ this.buffer = [];
27
+ this.bufferSize = opts.bufferSize || 100;
28
+ this.flushInterval = opts.flushInterval || 5000;
29
+ this.setupFlushInterval();
30
+ }
31
+ setupFlushInterval() {
32
+ setInterval(() => {
33
+ this.flush();
34
+ }, this.flushInterval);
35
+ }
36
+ async flush() {
37
+ if (this.buffer.length === 0) return;
38
+ const logs = this.buffer.splice(0, this.buffer.length);
39
+ const date = new Date().toISOString().split('T')[0];
40
+ const key = `${this.prefix}/${date}/${Date.now()}.json`;
41
+ try {
42
+ const command = new PutObjectCommand({
43
+ Bucket: this.bucket,
44
+ Key: key,
45
+ Body: JSON.stringify(logs),
46
+ ContentType: 'application/json'
47
+ });
48
+ await s3Client.send(command);
49
+ } catch (error) {
50
+ console.error('Failed to write logs to S3:', {
51
+ error: error.message,
52
+ code: error.code,
53
+ bucket: this.bucket,
54
+ key: key,
55
+ region: process.env.AWS_REGION,
56
+ stack: error.stack
57
+ });
58
+ // Put the logs back in the buffer
59
+ this.buffer.unshift(...logs);
60
+ }
61
+ }
62
+ log(info, callback) {
63
+ setImmediate(() => {
64
+ this.emit('logged', info);
65
+ });
66
+ this.buffer.push({
67
+ timestamp: new Date().toISOString(),
68
+ ...info
69
+ });
70
+ if (this.buffer.length >= this.bufferSize) {
71
+ this.flush();
72
+ }
73
+ callback();
74
+ }
75
+ }
76
+ module.exports = {
77
+ S3Transport
78
+ };
@@ -1,18 +1,23 @@
1
1
  "use strict";
2
2
 
3
- const jwt = require('jsonwebtoken');
4
- // const User = require('../models/user');
5
-
6
- exports.validateToken = async (req, res, next) => {
3
+ const jwt = require("jsonwebtoken");
4
+ const generateToken = user => {
5
+ return jwt.sign({
6
+ userId: user.userId
7
+ }, process.env.JWT_SECRET, {
8
+ expiresIn: process.env.JWT_EXPIRES_IN || '24h'
9
+ });
10
+ };
11
+ const validateToken = async (req, res, next) => {
7
12
  try {
8
13
  let token;
9
14
 
10
15
  // Check if token exists in headers
11
- if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
12
- token = req.headers.authorization.split(' ')[1];
16
+ if (req.headers.authorization && req.headers.authorization.startsWith("Bearer")) {
17
+ token = req.headers.authorization.split(" ")[1];
13
18
  }
14
19
  if (!token) {
15
- return res.error('Not authorized to access this route', 401);
20
+ return res.error("Not authorized to access this route", 401);
16
21
  }
17
22
  try {
18
23
  // Verify token
@@ -29,12 +34,32 @@ exports.validateToken = async (req, res, next) => {
29
34
  req.userId = decoded.userId;
30
35
  next();
31
36
  } catch (error) {
32
- return res.error('Not authorized to access this route', 401, error);
37
+ return res.error("Not authorized to access this route", 401, error);
33
38
  }
34
39
  } catch (error) {
35
- return res.error('Error authenticating user', 500, error);
40
+ return res.error("Error authenticating user", 500, error);
36
41
  }
37
42
  };
43
+ const validateAuth = (options = {}) => {
44
+ const {
45
+ publicPaths = ["/auth", "/", "/status", "/swagger"],
46
+ publicMethods = ["OPTIONS"]
47
+ } = options;
48
+ return async (req, res, next) => {
49
+ // Skip auth validation for public paths
50
+ if (publicPaths.some(path => req.path.startsWith(path))) {
51
+ return next();
52
+ }
53
+
54
+ // Skip auth validation for public methods
55
+ if (publicMethods.includes(req.method)) {
56
+ return next();
57
+ }
58
+
59
+ // Use the original validateToken middleware for protected routes
60
+ return validateToken(req, res, next);
61
+ };
62
+ };
38
63
 
39
64
  // exports.authorize = (...roles) => {
40
65
  // return (req, res, next) => {
@@ -43,4 +68,9 @@ exports.validateToken = async (req, res, next) => {
43
68
  // }
44
69
  // next();
45
70
  // };
46
- // };
71
+ // };
72
+
73
+ module.exports = {
74
+ validateAuth,
75
+ generateToken
76
+ };
@@ -1,17 +1,10 @@
1
1
  "use strict";
2
2
 
3
- const logger = require("../services/logger");
4
3
  const errorCatcher = fn => (req, res, next) => {
5
- Promise.resolve(fn(req, res, next)).catch(next);
4
+ Promise.resolve(fn(req, res, next)).catch(res.error);
6
5
  };
7
6
  const errorHandler = (err, req, res, next) => {
8
- logger.error("Error occurred", {
9
- error: err.message,
10
- stack: err.stack,
11
- path: req.path,
12
- method: req.method
13
- });
14
- return res.error(err.message, err.statusCode, err.details);
7
+ return res.error(err);
15
8
  };
16
9
  module.exports = {
17
10
  errorCatcher,
@@ -1,22 +1,95 @@
1
1
  "use strict";
2
2
 
3
- const logger = require("../services/logger");
4
- const requestLogger = (req, res, next) => {
3
+ const logger = require("../logger");
4
+ const requestHandler = (req, res, next) => {
5
5
  try {
6
- // Only log the request body, redacting sensitive information
7
- const logBody = {
8
- ...req.body
6
+ // Add request timestamp
7
+ req.requestTime = new Date().toISOString();
8
+
9
+ // Add request ID for tracking
10
+ req.requestId = req.headers['x-request-id'] || Math.random().toString(36).substring(2, 15);
11
+
12
+ // Set default response headers
13
+ res.setHeader('X-Request-ID', req.requestId);
14
+ res.setHeader('X-Request-Time', req.requestTime);
15
+
16
+ // Log the incoming request with details
17
+ const requestDetails = {
18
+ method: req.method,
19
+ path: req.path,
20
+ query: req.query,
21
+ ip: req.ip,
22
+ userAgent: req.headers['user-agent'],
23
+ requestId: req.requestId,
24
+ timestamp: req.requestTime
9
25
  };
10
- if (logBody.password) logBody.password = "[REDACTED]";
11
- if (logBody.token) logBody.token = "[REDACTED]";
12
- logger.info(`${req.method} ${req.path}`, logBody);
26
+
27
+ // Log request body if present, redacting sensitive information
28
+ if (Object.keys(req.body).length > 0) {
29
+ const logBody = {
30
+ ...req.body
31
+ };
32
+ if (logBody.password) logBody.password = "[REDACTED]";
33
+ if (logBody.token) logBody.token = "[REDACTED]";
34
+ requestDetails.body = logBody;
35
+ }
36
+ logger.info(`Incoming request: ${req.method} ${req.path}`, requestDetails);
37
+
38
+ // Add error handler to response object if not already present
39
+ if (!res.error) {
40
+ res.error = (message, statusCode = 500, error = null) => {
41
+ logger.error(message, {
42
+ statusCode,
43
+ requestId: req.requestId,
44
+ error
45
+ });
46
+ const response = {
47
+ success: false,
48
+ message,
49
+ requestId: req.requestId
50
+ };
51
+
52
+ // Include error in response if available
53
+ if (error !== null) {
54
+ response.error = error;
55
+ }
56
+ return res.status(statusCode).json(response);
57
+ };
58
+ }
59
+
60
+ // Add success handler to response object if not already present
61
+ if (!res.success) {
62
+ res.success = (message = 'Success', statusCode = 200, data = null) => {
63
+ logger.info(message, {
64
+ statusCode,
65
+ requestId: req.requestId,
66
+ data
67
+ });
68
+ // Create response object
69
+ const response = {
70
+ success: true,
71
+ message,
72
+ requestId: req.requestId
73
+ };
74
+
75
+ // Add data to response and log if available
76
+ if (data !== null) {
77
+ response.data = data;
78
+ }
79
+ return res.status(statusCode).json(response);
80
+ };
81
+ }
82
+
83
+ // Continue to the next middleware
13
84
  next();
14
85
  } catch (error) {
15
- // If logging fails, still continue with the request
16
- console.error("Error logging request:", error);
17
- next();
86
+ logger.error('Error in request handler', {
87
+ error,
88
+ requestId: req.requestId
89
+ });
90
+ return res.error('Internal server error', 500, error);
18
91
  }
19
92
  };
20
93
  module.exports = {
21
- requestLogger
94
+ requestHandler
22
95
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "powr-sdk-api",
3
- "version": "1.2.2",
3
+ "version": "1.3.1",
4
4
  "description": "Shared API core library for PowrStack projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",