UNPKG

guardflux

Version:

A light callable lib to keep your API alive

157 lines (156 loc) 8.55 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.schema = void 0; exports.getDriver = getDriver; exports.checkObject = checkObject; exports.rateLimit = rateLimit; const core_1 = require("@mikro-orm/core"); const entity_1 = require("./lib/entity"); const constants_1 = require("./lib/constants"); const messages_1 = require("./lib/messages"); const mongodb_1 = require("@mikro-orm/mongodb"); const mysql_1 = require("@mikro-orm/mysql"); const postgresql_1 = require("@mikro-orm/postgresql"); const helpers_1 = require("./lib/helpers"); const Joi = require("joi"); /** * Returns the appropriate MikroORM driver based on the specified database type. * * @param dbType - The type of the database. It can be one of 'postgresql', 'mysql', or 'mongodb'. * @returns The MikroORM driver for the specified database type. * @throws An error if the provided database type is not supported. */ function getDriver(dbType) { switch (dbType) { case 'postgresql': return postgresql_1.PostgreSqlDriver; // Returns the PostgreSQL driver case 'mysql': return mysql_1.MySqlDriver; // Returns the MySQL driver case 'mongodb': return mongodb_1.MongoDriver; // Returns the MongoDB driver default: throw new Error('Unsupported database type'); // Throws an error if the database type is not recognized } } /** * The schema constant is initialized as a Joi Root instance, * which provides the main API for creating schemas. * * @constant {Joi.Root} schema - The root Joi object used for schema validation. */ exports.schema = Joi; // Exports the Joi root object for use in validation /** * Checks if an object conforms to a specified Joi schema and returns the validation result. * * @param {any} obj - The object to validate against the schema. * @param {Joi.ObjectSchema<any>} schema - The Joi schema to validate the object against. * @param {boolean} [devMode=true] - Flag to enable or disable debugging logs. Default is true. * @returns {Promise<CheckResult>} - A promise that resolves to a CheckResult object containing * the validation status and any log information. */ function checkObject(obj_1, schema_1) { return __awaiter(this, arguments, void 0, function* (obj, schema, devMode = true) { let result = { isValid: false, // Initialize result with isValid set to false }; // Check if the object is empty if ((0, helpers_1.isObjectEmpty)(obj)) { result.log = messages_1.emptyObj; // Log the empty object message return result; // Return the result early } try { // Validate the object against the schema asynchronously yield schema.validateAsync(obj).then(() => { result.isValid = true; // Set isValid to true if validation passes }); } catch (error) { // If validation fails, log the error result.log = error; } // Debugging log if in development mode (0, helpers_1.devDebugger)(result, devMode); return result; // Return the result object }); } /** * Implements rate limiting for a user based on specified options. * This function checks the user's request count and manages their rate limit status in the database. * * @param {string} userId - The unique identifier for the user to apply rate limiting. * @param {RateLimitOptions} options - Options defining the rate limiting parameters, including the route and maximum requests. * @param {DbConfig} dbConfig - Configuration details for connecting to the database. * @param {boolean} [devMode=true] - Optional flag to enable debugging output. Defaults to true. * @returns {Promise<CheckResult>} - A promise that resolves to a CheckResult object containing * the validation status and any log information. */ function rateLimit(userId_1, options_1, dbConfig_1) { return __awaiter(this, arguments, void 0, function* (userId, options, dbConfig, devMode = true) { let result = { isValid: true, // Initialize result as valid }; // Configuration for the MikroORM connection const config = { dbName: dbConfig.dbName || constants_1.dbDefualtName, // Use provided DB name or default clientUrl: dbConfig.dbURI, // MongoDB connection URI entities: [entity_1.RateLimit], // Specify the RateLimit entity to manage debug: dbConfig.dbDebug, // Debug mode from DB configuration driver: getDriver(dbConfig.dbType), // Determine the database driver based on type allowGlobalContext: true // Allow usage of global context for ORM }; // Initialize MikroORM const orm = yield core_1.MikroORM.init(config); const entityManager = orm.em.fork(); // Create a fork of the entity manager for isolated operations const currentTime = new Date(); // Get the current time const cycleStart = new Date(currentTime.getTime() - options.cycleTime * 1000); // Calculate the start time of the current cycle // Find the current rate limit record for the user and route let rateLimit = yield entityManager.findOne(entity_1.RateLimit, { userId: userId, route: options.route }); if (!rateLimit) { // If no rate limit record exists, create a new one rateLimit = new entity_1.RateLimit(); rateLimit.userId = userId; // Set user ID rateLimit.route = options.route; // Set the current route rateLimit.requestCount = 1; // Initialize request count rateLimit.lastRequest = currentTime; // Set the last request time (0, helpers_1.devDebugger)(rateLimit, devMode); // Log the new rate limit record for debugging entityManager.create(entity_1.RateLimit, rateLimit); // Create the new entity yield entityManager.flush(); // Save changes to the database return result; // Return valid result as the rate limit is not exceeded } else { // If the rate limit record exists, check the last request time if (rateLimit.lastRequest <= cycleStart) { // If the last request is older than the cycle start, reset the count rateLimit.requestCount = 1; // Reset request count rateLimit.lastRequest = currentTime; // Update last request time (0, helpers_1.devDebugger)(rateLimit, devMode); // Log the updated rate limit record for debugging yield entityManager.persistAndFlush(rateLimit); // Save changes to the database return result; // Return valid result as the rate limit is not exceeded } // If the request count is below the maximum allowed if (rateLimit.requestCount < options.maxRequests) { rateLimit.requestCount++; // Increment the request count rateLimit.lastRequest = currentTime; // Update last request time (0, helpers_1.devDebugger)(rateLimit, devMode); // Log the updated rate limit record for debugging yield entityManager.persistAndFlush(rateLimit); // Save changes to the database return result; // Return valid result as the rate limit is not exceeded } } // If none of the above conditions are met, the rate limit has been reached result = { isValid: false, // Set result as invalid log: messages_1.userReachMaxRateLimit // Log the maximum rate limit reached }; (0, helpers_1.devDebugger)(result, devMode); // Log the result for debugging return result; // Return the result object }); }