@hastehaul/common 1.0.17 → 1.0.19

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.
@@ -1,6 +1,7 @@
1
1
  import IORedis from "ioredis";
2
2
  /**
3
- * A wrapper class for the Redis client to manage connections and provide a centralized client instance.
3
+ * A wrapper class for the Redis client. This class manages connections and provides
4
+ * a centralized client instance for a Redis database.
4
5
  */
5
6
  export declare class RedisWrapper {
6
7
  private _redisClient?;
@@ -14,11 +15,14 @@ export declare class RedisWrapper {
14
15
  */
15
16
  get client(): IORedis;
16
17
  /**
17
- * Connect to the Redis server using the specified host and port.
18
- *
19
- * The client instance will be stored in the `_redisClient` property for later access.
20
- */
21
- connect(): void;
18
+ * Connect to the Redis server using the specified host and port.
19
+ *
20
+ * The client instance will be stored in the `_redisClient` property for later access.
21
+ *
22
+ * @param {string} host - The Redis server host address (default is "customer-redis-srv").
23
+ * @param {number} port - The Redis server port number (default is 6379).
24
+ */
25
+ connect(host?: string, port?: number): void;
22
26
  }
23
27
  /**
24
28
  * Singleton instance of the RedisWrapper class to provide a centralized Redis client connection.
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.redisWrapper = exports.RedisWrapper = void 0;
7
7
  const ioredis_1 = __importDefault(require("ioredis"));
8
8
  /**
9
- * A wrapper class for the Redis client to manage connections and provide a centralized client instance.
9
+ * A wrapper class for the Redis client. This class manages connections and provides
10
+ * a centralized client instance for a Redis database.
10
11
  */
11
12
  class RedisWrapper {
12
13
  constructor() {
@@ -25,12 +26,15 @@ class RedisWrapper {
25
26
  return this._redisClient;
26
27
  }
27
28
  /**
28
- * Connect to the Redis server using the specified host and port.
29
- *
30
- * The client instance will be stored in the `_redisClient` property for later access.
31
- */
32
- connect() {
33
- this._redisClient = new ioredis_1.default({ host: this.host, port: this.port, maxRetriesPerRequest: null });
29
+ * Connect to the Redis server using the specified host and port.
30
+ *
31
+ * The client instance will be stored in the `_redisClient` property for later access.
32
+ *
33
+ * @param {string} host - The Redis server host address (default is "customer-redis-srv").
34
+ * @param {number} port - The Redis server port number (default is 6379).
35
+ */
36
+ connect(host, port) {
37
+ this._redisClient = new ioredis_1.default({ host: host || this.host, port: port || this.port, maxRetriesPerRequest: null });
34
38
  this._redisClient.on("connect", function () {
35
39
  console.info("Redis Server Connected!");
36
40
  });
@@ -0,0 +1,30 @@
1
+ import { StatusCodes } from '../utils/enums';
2
+ import { CustomError } from './custom-error';
3
+ /**
4
+ * Custom error class representing a "Not Authorized" error.
5
+ *
6
+ * The "NotAuthorizedError" class extends the base "CustomError" class to handle errors related to unauthorized access to a resource or action.
7
+ * It sets the HTTP status code to 401 (UNAUTHORIZED) and provides a default error message of "Not Authorized".
8
+ * Subclasses can customize the error message or additional fields as needed by overriding the "serializeErrors" method.
9
+ */
10
+ export declare class NotAuthorizedError extends CustomError {
11
+ /**
12
+ * HTTP status code for the "Not Authorized" error.
13
+ */
14
+ statusCode: StatusCodes;
15
+ /**
16
+ * Creates a new instance of the "NotAuthorizedError" class with a default error message of "Not Authorized".
17
+ */
18
+ constructor();
19
+ /**
20
+ * Serializes the error to be sent as a response to the client.
21
+ *
22
+ * The "serializeErrors" method returns an array containing an object with the error message for the "Not Authorized" error.
23
+ * Subclasses can override this method to provide custom error serialization.
24
+ *
25
+ * @returns An array containing an object with the error message for the "Not Authorized" error.
26
+ */
27
+ serializeErrors(): {
28
+ message: string;
29
+ }[];
30
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotAuthorizedError = void 0;
4
+ const enums_1 = require("../utils/enums");
5
+ const custom_error_1 = require("./custom-error");
6
+ /**
7
+ * Custom error class representing a "Not Authorized" error.
8
+ *
9
+ * The "NotAuthorizedError" class extends the base "CustomError" class to handle errors related to unauthorized access to a resource or action.
10
+ * It sets the HTTP status code to 401 (UNAUTHORIZED) and provides a default error message of "Not Authorized".
11
+ * Subclasses can customize the error message or additional fields as needed by overriding the "serializeErrors" method.
12
+ */
13
+ class NotAuthorizedError extends custom_error_1.CustomError {
14
+ /**
15
+ * Creates a new instance of the "NotAuthorizedError" class with a default error message of "Not Authorized".
16
+ */
17
+ constructor() {
18
+ super('Not Authorized');
19
+ /**
20
+ * HTTP status code for the "Not Authorized" error.
21
+ */
22
+ this.statusCode = enums_1.StatusCodes.UNAUTHORIZED;
23
+ // Ensures correct prototype chain for subclassing.
24
+ Object.setPrototypeOf(this, NotAuthorizedError.prototype);
25
+ }
26
+ /**
27
+ * Serializes the error to be sent as a response to the client.
28
+ *
29
+ * The "serializeErrors" method returns an array containing an object with the error message for the "Not Authorized" error.
30
+ * Subclasses can override this method to provide custom error serialization.
31
+ *
32
+ * @returns An array containing an object with the error message for the "Not Authorized" error.
33
+ */
34
+ serializeErrors() {
35
+ return [{ message: 'Not authorized' }];
36
+ }
37
+ }
38
+ exports.NotAuthorizedError = NotAuthorizedError;
@@ -0,0 +1,30 @@
1
+ import { StatusCodes } from '../utils/enums';
2
+ import { CustomError } from './custom-error';
3
+ /**
4
+ * Custom error class representing a "Resource Not Found" error.
5
+ *
6
+ * The "ResourceNotFound" class extends the base "CustomError" class to handle errors related to resources that cannot be found.
7
+ * It sets the HTTP status code to 404 (NOT_FOUND) and provides a default error message of "Resource not found".
8
+ * Subclasses can customize the error message or additional fields as needed by overriding the "serializeErrors" method.
9
+ */
10
+ export declare class ResourceNotFound extends CustomError {
11
+ /**
12
+ * HTTP status code for the "Resource Not Found" error.
13
+ */
14
+ statusCode: StatusCodes;
15
+ /**
16
+ * Creates a new instance of the "ResourceNotFound" class with a default error message of "Resource not found".
17
+ */
18
+ constructor();
19
+ /**
20
+ * Serializes the error to be sent as a response to the client.
21
+ *
22
+ * The "serializeErrors" method returns an array containing an object with the error message for the "Resource Not Found" error.
23
+ * Subclasses can override this method to provide custom error serialization.
24
+ *
25
+ * @returns An array containing an object with the error message for the "Resource Not Found" error.
26
+ */
27
+ serializeErrors(): {
28
+ message: string;
29
+ }[];
30
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResourceNotFound = void 0;
4
+ const enums_1 = require("../utils/enums");
5
+ const custom_error_1 = require("./custom-error");
6
+ /**
7
+ * Custom error class representing a "Resource Not Found" error.
8
+ *
9
+ * The "ResourceNotFound" class extends the base "CustomError" class to handle errors related to resources that cannot be found.
10
+ * It sets the HTTP status code to 404 (NOT_FOUND) and provides a default error message of "Resource not found".
11
+ * Subclasses can customize the error message or additional fields as needed by overriding the "serializeErrors" method.
12
+ */
13
+ class ResourceNotFound extends custom_error_1.CustomError {
14
+ /**
15
+ * Creates a new instance of the "ResourceNotFound" class with a default error message of "Resource not found".
16
+ */
17
+ constructor() {
18
+ super('Resource not found');
19
+ /**
20
+ * HTTP status code for the "Resource Not Found" error.
21
+ */
22
+ this.statusCode = enums_1.StatusCodes.NOT_FOUND;
23
+ Object.setPrototypeOf(this, ResourceNotFound.prototype);
24
+ }
25
+ /**
26
+ * Serializes the error to be sent as a response to the client.
27
+ *
28
+ * The "serializeErrors" method returns an array containing an object with the error message for the "Resource Not Found" error.
29
+ * Subclasses can override this method to provide custom error serialization.
30
+ *
31
+ * @returns An array containing an object with the error message for the "Resource Not Found" error.
32
+ */
33
+ serializeErrors() {
34
+ return [{ message: 'Resource Not Found' }];
35
+ }
36
+ }
37
+ exports.ResourceNotFound = ResourceNotFound;
@@ -0,0 +1,33 @@
1
+ import { CustomError } from './custom-error';
2
+ /**
3
+ * Custom error class representing a "Too Many Requests" error.
4
+ *
5
+ * The "TooManyRequestError" class extends the base "CustomError" class to handle errors related to receiving too many requests from a client within a specific time frame.
6
+ * It sets the HTTP status code to 429 (TOO_MANY_REQUESTS) and provides a default error message of "Too Many Requests".
7
+ * The class also includes a `retrySec` property to specify the number of seconds after which the client can retry the request.
8
+ * Subclasses can customize the error message or additional fields as needed by overriding the "serializeErrors" method.
9
+ */
10
+ export declare class TooManyRequestError extends CustomError {
11
+ retrySec: string;
12
+ /**
13
+ * HTTP status code for the "Too Many Requests" error.
14
+ */
15
+ statusCode: number;
16
+ /**
17
+ * Creates a new instance of the "TooManyRequestError" class with a default error message of "Too Many Requests".
18
+ *
19
+ * @param retrySec The number of seconds after which the client can retry the request.
20
+ */
21
+ constructor(retrySec: string);
22
+ /**
23
+ * Serializes the error to be sent as a response to the client.
24
+ *
25
+ * The "serializeErrors" method returns an array containing an object with the error message for the "Too Many Requests" error.
26
+ * Subclasses can override this method to provide custom error serialization.
27
+ *
28
+ * @returns An array containing an object with the error message for the "Too Many Requests" error.
29
+ */
30
+ serializeErrors(): {
31
+ message: string;
32
+ }[];
33
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TooManyRequestError = void 0;
4
+ const enums_1 = require("../utils/enums");
5
+ const custom_error_1 = require("./custom-error");
6
+ /**
7
+ * Custom error class representing a "Too Many Requests" error.
8
+ *
9
+ * The "TooManyRequestError" class extends the base "CustomError" class to handle errors related to receiving too many requests from a client within a specific time frame.
10
+ * It sets the HTTP status code to 429 (TOO_MANY_REQUESTS) and provides a default error message of "Too Many Requests".
11
+ * The class also includes a `retrySec` property to specify the number of seconds after which the client can retry the request.
12
+ * Subclasses can customize the error message or additional fields as needed by overriding the "serializeErrors" method.
13
+ */
14
+ class TooManyRequestError extends custom_error_1.CustomError {
15
+ /**
16
+ * Creates a new instance of the "TooManyRequestError" class with a default error message of "Too Many Requests".
17
+ *
18
+ * @param retrySec The number of seconds after which the client can retry the request.
19
+ */
20
+ constructor(retrySec) {
21
+ super('Too Many Requests');
22
+ this.retrySec = retrySec;
23
+ /**
24
+ * HTTP status code for the "Too Many Requests" error.
25
+ */
26
+ this.statusCode = enums_1.StatusCodes.TOO_MANY_REQUEST;
27
+ Object.setPrototypeOf(this, TooManyRequestError.prototype);
28
+ }
29
+ /**
30
+ * Serializes the error to be sent as a response to the client.
31
+ *
32
+ * The "serializeErrors" method returns an array containing an object with the error message for the "Too Many Requests" error.
33
+ * Subclasses can override this method to provide custom error serialization.
34
+ *
35
+ * @returns An array containing an object with the error message for the "Too Many Requests" error.
36
+ */
37
+ serializeErrors() {
38
+ return [
39
+ { message: `Too Many Requests. Try again later` }
40
+ ];
41
+ }
42
+ }
43
+ exports.TooManyRequestError = TooManyRequestError;
package/build/index.d.ts CHANGED
@@ -49,6 +49,9 @@ export * from "./errors/not-found-error";
49
49
  * The "SystemError" class represents a specific "System Error" that can occur due to unexpected issues in the system.
50
50
  */
51
51
  export * from "./errors/system-error";
52
+ export * from "./errors/too-many-request-error";
53
+ export * from "./errors/resource-not-found";
54
+ export * from "./errors/not-authorized-error";
52
55
  /**
53
56
  * Re-exports the "currentUser" middleware from the "current-user" module.
54
57
  *
@@ -65,6 +68,9 @@ export * from "./middlewares/current-user";
65
68
  * If the error is not a custom error, a generic error response is sent with a 500 status code and a default error message.
66
69
  */
67
70
  export * from "./middlewares/error-handler";
71
+ export * from "./middlewares/is-allowed";
72
+ export * from "./middlewares/validate-body";
73
+ export * from "./middlewares/require-auth";
68
74
  /**
69
75
  *? Re-exports all the enums from the "enums" module.
70
76
  *
@@ -79,6 +85,7 @@ export * from "./utils/enums";
79
85
  * These functions are used for dynamic loading, configuration, and other file-related operations.
80
86
  */
81
87
  export * from "./utils/read-dir";
88
+ export * from "./utils/schemas";
82
89
  /**
83
90
  *? Re-exports all the contents from the "base-producers" module.
84
91
  *
package/build/index.js CHANGED
@@ -67,6 +67,12 @@ __exportStar(require("./errors/not-found-error"), exports);
67
67
  * The "SystemError" class represents a specific "System Error" that can occur due to unexpected issues in the system.
68
68
  */
69
69
  __exportStar(require("./errors/system-error"), exports);
70
+ //TODO: DOCUMENT
71
+ __exportStar(require("./errors/too-many-request-error"), exports);
72
+ //TODO: DOCUMENT
73
+ __exportStar(require("./errors/resource-not-found"), exports);
74
+ //TODO: DOCUMENT
75
+ __exportStar(require("./errors/not-authorized-error"), exports);
70
76
  //* Import and re-export multiple middleware modules.
71
77
  /**
72
78
  * Re-exports the "currentUser" middleware from the "current-user" module.
@@ -84,6 +90,12 @@ __exportStar(require("./middlewares/current-user"), exports);
84
90
  * If the error is not a custom error, a generic error response is sent with a 500 status code and a default error message.
85
91
  */
86
92
  __exportStar(require("./middlewares/error-handler"), exports);
93
+ //TODO: DOCUMENT
94
+ __exportStar(require("./middlewares/is-allowed"), exports);
95
+ //TODO: DOCUMENT
96
+ __exportStar(require("./middlewares/validate-body"), exports);
97
+ //TODO: DOCUMENT
98
+ __exportStar(require("./middlewares/require-auth"), exports);
87
99
  //* Import and re-export multiple modules for enums, base classes, and read-dir functionality.
88
100
  /**
89
101
  *? Re-exports all the enums from the "enums" module.
@@ -99,6 +111,8 @@ __exportStar(require("./utils/enums"), exports);
99
111
  * These functions are used for dynamic loading, configuration, and other file-related operations.
100
112
  */
101
113
  __exportStar(require("./utils/read-dir"), exports);
114
+ //TODO: DOCUMENT
115
+ __exportStar(require("./utils/schemas"), exports);
102
116
  /**
103
117
  *? Re-exports all the contents from the "base-producers" module.
104
118
  *
@@ -64,7 +64,6 @@ const currentUser = (req, res, next) => __awaiter(void 0, void 0, void 0, functi
64
64
  // If the token is expired, you may consider refreshing the token or taking appropriate actions.
65
65
  // Uncomment the following line if you want to handle token expiration using the AuthController.
66
66
  // await AuthController.refreshToken(req, res);
67
- // await AuthController.refreshToken(req, res)
68
67
  }
69
68
  else {
70
69
  // If any other error occurs during token verification, set currentUser to null.
@@ -15,8 +15,6 @@ const errorHandler = (err, req, res, next) => {
15
15
  if (err instanceof custom_error_1.CustomError) {
16
16
  return res.status(err.statusCode).send({ errors: err.serializeErrors() });
17
17
  }
18
- res
19
- .status(enums_1.StatusCodes.BAD_REQUEST)
20
- .send({ errors: [{ message: "Something went wrong" }] });
18
+ res.status(enums_1.StatusCodes.BAD_REQUEST).send({ errors: [{ message: "Something went wrong" }] });
21
19
  };
22
20
  exports.errorHandler = errorHandler;
@@ -0,0 +1,24 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ /**
3
+ * Middleware to check if a user is allowed to perform a specific action on a resource based on their role and permissions.
4
+ * If the user is not authorized, it throws a NotAuthorizedError to indicate access denied.
5
+ *
6
+ * @param req - The Express request object.
7
+ * @param res - The Express response object.
8
+ * @param next - The next middleware function.
9
+ * @param hasVersion - Set to true if the API path includes the version (e.g., /api/v1/...). Default is false.
10
+ *
11
+ * @throws BadRequestError - If the action is not supported or if the session has expired.
12
+ * @throws ResourceNotFound - If the requested resource is not found.
13
+ * @throws NotAuthorizedError - If the user is not authorized to perform the action on the resource.
14
+ *
15
+ * @example
16
+ * ```js
17
+ * // Route that requires authorization based on user role and permissions
18
+ * router.get("/resource/:id", isAllowed, (req, res) => {
19
+ * // Only authorized users with the appropriate permissions can access this route
20
+ * res.send("You are authorized!");
21
+ * });
22
+ * ```
23
+ */
24
+ export declare const isAllowed: (req: Request, res: Response, next: NextFunction, hasVersion?: boolean) => void;
@@ -0,0 +1,71 @@
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.isAllowed = void 0;
7
+ const accesscontrol_1 = __importDefault(require("@vsky/accesscontrol"));
8
+ const resource_not_found_1 = require("../errors/resource-not-found");
9
+ const not_authorized_error_1 = require("../errors/not-authorized-error");
10
+ const bad_request_error_1 = require("../errors/bad-request-error");
11
+ // Mapping object for HTTP method to action
12
+ const methodToAction = {
13
+ GET: "view",
14
+ POST: "create",
15
+ DELETE: "delete",
16
+ PUT: "update",
17
+ PATCH: "update",
18
+ };
19
+ /**
20
+ * Middleware to check if a user is allowed to perform a specific action on a resource based on their role and permissions.
21
+ * If the user is not authorized, it throws a NotAuthorizedError to indicate access denied.
22
+ *
23
+ * @param req - The Express request object.
24
+ * @param res - The Express response object.
25
+ * @param next - The next middleware function.
26
+ * @param hasVersion - Set to true if the API path includes the version (e.g., /api/v1/...). Default is false.
27
+ *
28
+ * @throws BadRequestError - If the action is not supported or if the session has expired.
29
+ * @throws ResourceNotFound - If the requested resource is not found.
30
+ * @throws NotAuthorizedError - If the user is not authorized to perform the action on the resource.
31
+ *
32
+ * @example
33
+ * ```js
34
+ * // Route that requires authorization based on user role and permissions
35
+ * router.get("/resource/:id", isAllowed, (req, res) => {
36
+ * // Only authorized users with the appropriate permissions can access this route
37
+ * res.send("You are authorized!");
38
+ * });
39
+ * ```
40
+ */
41
+ const isAllowed = (req, res, next, hasVersion = false) => {
42
+ var _a, _b;
43
+ let STABLEVERSION = `${process.env.STABLE_VERSION}`;
44
+ if (!STABLEVERSION) {
45
+ STABLEVERSION = "v1";
46
+ }
47
+ // Regular expression to match the route path and extract the resource
48
+ const regexString = `^\\/api\\/${hasVersion ? `${STABLEVERSION}\\/` : ""}(\\w+)(\\/.*)?$`;
49
+ const regex = new RegExp(regexString);
50
+ const path = req.originalUrl;
51
+ const match = path.match(regex);
52
+ const resource = match && match[1];
53
+ // Determine the action based on the HTTP method
54
+ const action = methodToAction[req.method.toUpperCase()];
55
+ if (!action) {
56
+ throw new bad_request_error_1.BadRequestError("Session expired. Please relogin.");
57
+ }
58
+ if (!resource) {
59
+ throw new resource_not_found_1.ResourceNotFound();
60
+ }
61
+ // Get the roles and role of the current user from the session
62
+ const roles = ((_a = req.currentUser) === null || _a === void 0 ? void 0 : _a.role_permission) || [];
63
+ const role = (_b = req.currentUser) === null || _b === void 0 ? void 0 : _b.role;
64
+ // Check if the user can perform the action on the resource
65
+ const canPerform = new accesscontrol_1.default(roles).canPerformAction(role, resource, action);
66
+ if (!canPerform) {
67
+ throw new not_authorized_error_1.NotAuthorizedError();
68
+ }
69
+ next();
70
+ };
71
+ exports.isAllowed = isAllowed;
@@ -0,0 +1,18 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ /**
3
+ * Middleware to check if a user is authenticated before allowing access to certain routes.
4
+ * If the user is not authenticated, it throws a NotAuthorizedError to indicate access denied.
5
+ * @param req The Express request object.
6
+ * @param res The Express response object.
7
+ * @param next The next middleware function.
8
+ * @throws NotAuthorizedError if the user is not authenticated.
9
+ * @example
10
+ * ```js
11
+ // Route that requires authentication
12
+ router.get('/protected', requireAuth, (req, res) => {
13
+ // Only authenticated users can access this route
14
+ res.send('You are authorized!');
15
+ });
16
+ * ```
17
+ */
18
+ export declare const requireAuth: (req: Request, res: Response, next: NextFunction) => void;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireAuth = void 0;
4
+ const not_authorized_error_1 = require("../errors/not-authorized-error");
5
+ /**
6
+ * Middleware to check if a user is authenticated before allowing access to certain routes.
7
+ * If the user is not authenticated, it throws a NotAuthorizedError to indicate access denied.
8
+ * @param req The Express request object.
9
+ * @param res The Express response object.
10
+ * @param next The next middleware function.
11
+ * @throws NotAuthorizedError if the user is not authenticated.
12
+ * @example
13
+ * ```js
14
+ // Route that requires authentication
15
+ router.get('/protected', requireAuth, (req, res) => {
16
+ // Only authenticated users can access this route
17
+ res.send('You are authorized!');
18
+ });
19
+ * ```
20
+ */
21
+ const requireAuth = (req, res, next) => {
22
+ if (!req.currentUser) {
23
+ throw new not_authorized_error_1.NotAuthorizedError();
24
+ }
25
+ next();
26
+ };
27
+ exports.requireAuth = requireAuth;
@@ -0,0 +1,57 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ /**
3
+ * Represents the required fields for each HTTP method.
4
+ * MethodRequiredProps is a mapping between HTTP methods ("POST", "DELETE", "PATCH", "PUT", "GET")
5
+ * and an object containing an array of required fields for that method.
6
+ */
7
+ type MethodRequiredProps = {
8
+ [key in "POST" | "DELETE" | "PATCH" | "PUT" | "GET"]: {
9
+ required: string[];
10
+ };
11
+ };
12
+ /**
13
+ * Represents the schema for validating request body parameters.
14
+ * - `fields`: An object mapping each parameter name to its expected type.
15
+ * - `required`: An optional array of parameter names that are required in the request body.
16
+ * - `optional`: An optional array of parameter names that are allowed but not required in the request body.
17
+ */
18
+ export type Schema = {
19
+ fields: {
20
+ [key: string]: string;
21
+ };
22
+ required?: string[] | MethodRequiredProps;
23
+ optional?: string[];
24
+ };
25
+ /**
26
+ * Class providing request body validation middleware.
27
+ */
28
+ export declare class RequestValidator {
29
+ private model;
30
+ /**
31
+ * Constructor for the RequestValidator class.
32
+ * @param model The schema defining the expected fields and types in the request body.
33
+ */
34
+ constructor(model: Schema);
35
+ /**
36
+ * Private method to validate required fields in the request body.
37
+ * @param obj The request body object.
38
+ * @param required The required fields or required fields for specific HTTP methods.
39
+ * @param method The HTTP method of the request.
40
+ * @returns An object containing the validation status and the element that caused the validation failure (if any).
41
+ */
42
+ private required;
43
+ /**
44
+ * Private method to check if the fields in the request body match the defined schema.
45
+ * @param obj The request body object.
46
+ */
47
+ private check;
48
+ /**
49
+ * Middleware function to validate the request body against the provided schema.
50
+ * @param req The Express request object.
51
+ * @param res The Express response object.
52
+ * @param next The next middleware function.
53
+ * @throws BadRequestError if any validation fails.
54
+ */
55
+ validateReqBody: (req: Request, res: Response, next: NextFunction) => Promise<void>;
56
+ }
57
+ export {};
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RequestValidator = void 0;
13
+ const bad_request_error_1 = require("../errors/bad-request-error");
14
+ /**
15
+ * Class providing request body validation middleware.
16
+ */
17
+ class RequestValidator {
18
+ /**
19
+ * Constructor for the RequestValidator class.
20
+ * @param model The schema defining the expected fields and types in the request body.
21
+ */
22
+ constructor(model) {
23
+ /**
24
+ * Middleware function to validate the request body against the provided schema.
25
+ * @param req The Express request object.
26
+ * @param res The Express response object.
27
+ * @param next The next middleware function.
28
+ * @throws BadRequestError if any validation fails.
29
+ */
30
+ this.validateReqBody = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
31
+ const paramsLength = Object.keys(req.params).length;
32
+ const bodyLength = Object.keys(req.body).length;
33
+ const method = req.method;
34
+ const methods = ["POST", "PUT", "DELETE", "PATCH", "GET"];
35
+ const obj = paramsLength > 0 && bodyLength > 0 ? Object.assign(Object.assign({}, req.params), req.body) : bodyLength > 0 ? req.body : req.params;
36
+ if (methods.includes(method)) {
37
+ if (this.model.required) {
38
+ const { status, element } = this.required(obj, this.model.required, method);
39
+ if (!status) {
40
+ throw new bad_request_error_1.BadRequestError(`Required field: ${element}`);
41
+ }
42
+ }
43
+ }
44
+ if (!obj.multiadd) {
45
+ this.check(obj);
46
+ }
47
+ else {
48
+ for (const element of obj.multiadd) {
49
+ this.check(element);
50
+ }
51
+ }
52
+ next();
53
+ });
54
+ this.model = model;
55
+ }
56
+ /**
57
+ * Private method to validate required fields in the request body.
58
+ * @param obj The request body object.
59
+ * @param required The required fields or required fields for specific HTTP methods.
60
+ * @param method The HTTP method of the request.
61
+ * @returns An object containing the validation status and the element that caused the validation failure (if any).
62
+ */
63
+ required(obj, required, method) {
64
+ const isArray = Array.isArray(required);
65
+ if (!obj.multiadd) {
66
+ const data = !isArray ? required[method]['required'] : required;
67
+ for (const requiredKey of data) {
68
+ if (!obj[requiredKey] || (typeof obj[requiredKey] === 'string' && !obj[requiredKey].trim())) {
69
+ return { status: false, element: requiredKey };
70
+ }
71
+ }
72
+ }
73
+ else {
74
+ if (isArray) {
75
+ for (const requiredKey of required) {
76
+ for (const element of obj.multiadd) {
77
+ if (!element[requiredKey]) {
78
+ return { status: false, element: requiredKey };
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ return { status: true, element: '' };
85
+ }
86
+ /**
87
+ * Private method to check if the fields in the request body match the defined schema.
88
+ * @param obj The request body object.
89
+ */
90
+ check(obj) {
91
+ var _a, _b;
92
+ for (const key of Object.keys(obj)) {
93
+ if (!this.model.fields[key] && !((_a = this.model.optional) === null || _a === void 0 ? void 0 : _a.includes(key))) {
94
+ throw new bad_request_error_1.BadRequestError(`Invalid parameter: ${key}`);
95
+ }
96
+ if (typeof obj[key] !== this.model.fields[key] && !((_b = this.model.optional) === null || _b === void 0 ? void 0 : _b.includes(key))) {
97
+ throw new bad_request_error_1.BadRequestError(`Parameter type mismatch: ${key}`);
98
+ }
99
+ }
100
+ }
101
+ }
102
+ exports.RequestValidator = RequestValidator;
@@ -0,0 +1,11 @@
1
+ import { Schema } from '../middlewares/validate-body';
2
+ export declare const RegisterSchema: Schema;
3
+ export declare const SigninSchema: Schema;
4
+ export declare const BranchSchema: Schema;
5
+ export declare const DenominationSchema: Schema;
6
+ export declare const CategorySchema: Schema;
7
+ export declare const WardSchema: Schema;
8
+ export declare const UserTypeSchema: Schema;
9
+ export declare const DelegateSchema: Schema;
10
+ export declare const CandidateSchema: Schema;
11
+ export declare const UserSchema: Schema;
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UserSchema = exports.CandidateSchema = exports.DelegateSchema = exports.UserTypeSchema = exports.WardSchema = exports.CategorySchema = exports.DenominationSchema = exports.BranchSchema = exports.SigninSchema = exports.RegisterSchema = void 0;
4
+ exports.RegisterSchema = {
5
+ fields: {
6
+ user_name: 'string',
7
+ user_type: 'string',
8
+ password: 'string',
9
+ email: 'string',
10
+ contact: 'string',
11
+ address: 'string',
12
+ },
13
+ required: ['user_name', 'user_type', 'password']
14
+ };
15
+ exports.SigninSchema = {
16
+ fields: {
17
+ password: 'string',
18
+ user_name: 'string',
19
+ },
20
+ required: ['password', 'user_name']
21
+ };
22
+ exports.BranchSchema = {
23
+ fields: {
24
+ id: 'string',
25
+ name: 'string',
26
+ ward_id: 'string',
27
+ include: 'string',
28
+ code: 'string',
29
+ status: 'boolean',
30
+ },
31
+ required: {
32
+ 'POST': { required: ['name', 'status', 'ward_id', 'code'] },
33
+ 'PUT': { required: ['id', 'ward_id'] },
34
+ 'PATCH': { required: [] },
35
+ 'DELETE': { required: ['id'] },
36
+ 'GET': { required: ['id'] },
37
+ },
38
+ optional: ['include', 'ward_id']
39
+ };
40
+ exports.DenominationSchema = {
41
+ fields: {
42
+ id: 'string',
43
+ include: 'string',
44
+ name: 'string',
45
+ status: 'boolean',
46
+ },
47
+ required: {
48
+ 'POST': { required: ['name', 'status'] },
49
+ 'PUT': { required: ['id'] },
50
+ 'PATCH': { required: [] },
51
+ 'DELETE': { required: ['id'] },
52
+ 'GET': { required: ['id'] },
53
+ },
54
+ optional: ['include']
55
+ };
56
+ exports.CategorySchema = {
57
+ fields: {
58
+ id: 'string',
59
+ name: 'string',
60
+ status: 'boolean',
61
+ },
62
+ required: {
63
+ 'POST': { required: ['name', 'status'] },
64
+ 'PUT': { required: ['id'] },
65
+ 'PATCH': { required: [] },
66
+ 'DELETE': { required: ['id'] },
67
+ 'GET': { required: ['id'] },
68
+ }
69
+ };
70
+ exports.WardSchema = {
71
+ fields: {
72
+ id: 'string',
73
+ name: 'string',
74
+ status: 'boolean',
75
+ },
76
+ required: {
77
+ 'POST': { required: ['name', 'status'] },
78
+ 'PUT': { required: ['id'] },
79
+ 'PATCH': { required: [] },
80
+ 'DELETE': { required: ['id'] },
81
+ 'GET': { required: ['id'] },
82
+ }
83
+ };
84
+ exports.UserTypeSchema = {
85
+ fields: {
86
+ id: 'string',
87
+ name: 'string',
88
+ status: 'boolean',
89
+ },
90
+ required: {
91
+ 'POST': { required: ['name', 'status'] },
92
+ 'PUT': { required: ['id'] },
93
+ 'PATCH': { required: [] },
94
+ 'DELETE': { required: ['id'] },
95
+ 'GET': { required: ['id'] },
96
+ }
97
+ };
98
+ exports.DelegateSchema = {
99
+ fields: {
100
+ id: 'string',
101
+ include: 'string',
102
+ name: 'string',
103
+ position: 'string',
104
+ voter_id_nnumber: 'string',
105
+ membership_number: 'string',
106
+ contact: 'string',
107
+ denomination_id: 'string',
108
+ status: 'boolean',
109
+ branch_id: 'string',
110
+ category_id: 'string',
111
+ is_potential_for: 'string',
112
+ multi_update: 'boolean'
113
+ },
114
+ required: {
115
+ 'POST': { required: ['name', 'status', 'category_id'] },
116
+ 'PUT': { required: ['id'] },
117
+ 'PATCH': { required: [] },
118
+ 'DELETE': { required: ['id'] },
119
+ 'GET': { required: ['id'] },
120
+ },
121
+ optional: ['include']
122
+ };
123
+ exports.CandidateSchema = {
124
+ fields: {
125
+ id: 'string',
126
+ include: 'string',
127
+ name: 'string',
128
+ position: 'string',
129
+ voter_id_nnumber: 'string',
130
+ membership_number: 'string',
131
+ contact: 'string',
132
+ address: 'string',
133
+ denomination: 'string',
134
+ email: 'string',
135
+ status: 'boolean',
136
+ branch_id: 'string',
137
+ delegate_id: 'string',
138
+ },
139
+ required: {
140
+ 'POST': { required: ['name', 'status', 'branch_id'] },
141
+ 'PUT': { required: ['id'] },
142
+ 'PATCH': { required: [] },
143
+ 'DELETE': { required: ['id'] },
144
+ 'GET': { required: ['id'] },
145
+ },
146
+ optional: ['include']
147
+ };
148
+ exports.UserSchema = {
149
+ fields: {
150
+ role: 'string',
151
+ password: 'string',
152
+ password_tries: 'number',
153
+ status: 'number',
154
+ ip_address: 'string',
155
+ employee_id: 'string',
156
+ company_id: 'string',
157
+ branch_id: 'string',
158
+ multiadd: 'object'
159
+ },
160
+ required: ['role', 'password', 'employee_id', 'company_id'],
161
+ optional: ['branch_id', 'multiadd']
162
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hastehaul/common",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  "typescript": "^5.1.6"
24
24
  },
25
25
  "dependencies": {
26
+ "@vsky/accesscontrol": "^3.0.14",
26
27
  "bullmq": "^4.6.3",
27
28
  "express": "^4.18.2",
28
29
  "ioredis": "^5.3.2",