From ab64b292c9bf0dab0e63da6de3cb12c0eb8ab3c2 Mon Sep 17 00:00:00 2001 From: Chirag <149593757+cj201199@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:20:53 +0530 Subject: [PATCH] Implemented ICICI API endpoints --- ecosystem.config.json | 16 + package.json | 46 + src/DTOs/index.js | 3 + src/api/ICICI/icici.api.js | 64 + src/api/index.js | 3 + src/app.js | 73 + src/config/config.js | 179 ++ src/config/logger.js | 26 + src/config/morgan.js | 33 + src/config/nodemailerConfig.js | 7 + src/config/oneSignal.config.js | 10 + src/config/roles.js | 12 + src/config/tokens.js | 10 + src/config/twilioClient.js | 10 + src/controllers/icici/icicibank.controller.js | 115 + src/controllers/index.js | 3 + src/data/data.json | 106 + src/docs/swaggerDef.js | 18 + src/index.js | 51 + src/keys/certificate.pem | 50 + src/keys/public_key.pem | 14 + src/keys/rsa_private_key.pem | 51 + src/middlewares/auth.js | 39 + src/middlewares/code.js | 11 + src/middlewares/error.js | 55 + src/middlewares/rateLimiter.js | 11 + src/middlewares/storage.js | 92 + src/middlewares/validate.js | 27 + src/models/index.js | 39 + src/routes/v1/icici/index.js | 5 + src/routes/v1/icici/user.routes.js | 10 + src/routes/v1/index.js | 27 + src/services/IAM/iam_principal.service.js | 60 + .../IAM/iam_principal_notification.service.js | 32 + src/services/access/tokenService.js | 8 + src/services/bcrypt/bcrypt.service.js | 13 + src/services/code/code.service.js | 45 + src/services/corporate/corporate.service.js | 52 + src/services/crypto/crypto.service.js | 62 + .../emailTemplate/otpSenderTemplate.js | 31 + .../emailTemplate/resetOtpTemplate.js | 65 + .../iamPrincipalOTP.service.js | 20 + src/services/index.js | 13 + src/services/industry/industry.service.js | 5 + src/services/token/token.service.js | 50 + src/utils/constant/corporate.constant.js | 26 + src/utils/constant/iam.constant.js | 14 + src/utils/handler/ApiError.handler.js | 41 + src/utils/handler/ApiResponse.handler.js | 19 + src/utils/handler/Async.handler.js | 11 + src/utils/handler/pick.handler.js | 21 + src/utils/helper/aesCrypto.helper.js | 21 + src/utils/helper/emailValidator.helper.js | 30 + src/utils/helper/fileValidator.helper.js | 12 + src/utils/helper/genrateCodeName.helper.js | 36 + src/utils/helper/notificationMsg.helper.js | 131 ++ src/utils/helper/otpGenrator.helper.js | 16 + .../transactionNumberGenrator.helper.js | 42 + src/validation/auth/admin.schema.js | 15 + src/validation/auth/biometric.schema.js | 17 + src/validation/auth/forgetPassword.schema.js | 10 + src/validation/auth/index.js | 10 + src/validation/auth/login.schema.js | 16 + src/validation/auth/otpVerification.schema.js | 10 + src/validation/auth/registration.schema.js | 41 + src/validation/auth/resetPaasword.schema.js | 27 + src/validation/auth/updatePassword.schema.js | 22 + src/validation/common/code.schema.js | 9 + src/validation/common/id.schema.js | 11 + src/validation/common/index.js | 5 + src/validation/common/search.schema.js | 8 + .../corporate/corporateQuickAdd.schema.js | 38 + .../corporate/createCorporate.schema.js | 99 + src/validation/corporate/index.js | 4 + src/validation/fileUpload/all.schema.js | 10 + src/validation/fileUpload/index.js | 3 + src/validation/icici/index.js | 3 + src/validation/icici/registration.schema.js | 99 + src/validation/index.js | 3 + yarn.lock | 2022 +++++++++++++++++ 80 files changed, 4574 insertions(+) create mode 100644 ecosystem.config.json create mode 100644 package.json create mode 100644 src/DTOs/index.js create mode 100644 src/api/ICICI/icici.api.js create mode 100644 src/api/index.js create mode 100644 src/app.js create mode 100644 src/config/config.js create mode 100644 src/config/logger.js create mode 100644 src/config/morgan.js create mode 100644 src/config/nodemailerConfig.js create mode 100644 src/config/oneSignal.config.js create mode 100644 src/config/roles.js create mode 100644 src/config/tokens.js create mode 100644 src/config/twilioClient.js create mode 100644 src/controllers/icici/icicibank.controller.js create mode 100644 src/controllers/index.js create mode 100644 src/data/data.json create mode 100644 src/docs/swaggerDef.js create mode 100644 src/index.js create mode 100644 src/keys/certificate.pem create mode 100644 src/keys/public_key.pem create mode 100644 src/keys/rsa_private_key.pem create mode 100644 src/middlewares/auth.js create mode 100644 src/middlewares/code.js create mode 100644 src/middlewares/error.js create mode 100644 src/middlewares/rateLimiter.js create mode 100644 src/middlewares/storage.js create mode 100644 src/middlewares/validate.js create mode 100644 src/models/index.js create mode 100644 src/routes/v1/icici/index.js create mode 100644 src/routes/v1/icici/user.routes.js create mode 100644 src/routes/v1/index.js create mode 100644 src/services/IAM/iam_principal.service.js create mode 100644 src/services/IAM/iam_principal_notification.service.js create mode 100644 src/services/access/tokenService.js create mode 100644 src/services/bcrypt/bcrypt.service.js create mode 100644 src/services/code/code.service.js create mode 100644 src/services/corporate/corporate.service.js create mode 100644 src/services/crypto/crypto.service.js create mode 100644 src/services/emailTemplate/otpSenderTemplate.js create mode 100644 src/services/emailTemplate/resetOtpTemplate.js create mode 100644 src/services/iam_principal_otp/iamPrincipalOTP.service.js create mode 100644 src/services/index.js create mode 100644 src/services/industry/industry.service.js create mode 100644 src/services/token/token.service.js create mode 100644 src/utils/constant/corporate.constant.js create mode 100644 src/utils/constant/iam.constant.js create mode 100644 src/utils/handler/ApiError.handler.js create mode 100644 src/utils/handler/ApiResponse.handler.js create mode 100644 src/utils/handler/Async.handler.js create mode 100644 src/utils/handler/pick.handler.js create mode 100644 src/utils/helper/aesCrypto.helper.js create mode 100644 src/utils/helper/emailValidator.helper.js create mode 100644 src/utils/helper/fileValidator.helper.js create mode 100644 src/utils/helper/genrateCodeName.helper.js create mode 100644 src/utils/helper/notificationMsg.helper.js create mode 100644 src/utils/helper/otpGenrator.helper.js create mode 100644 src/utils/helper/transactionNumberGenrator.helper.js create mode 100644 src/validation/auth/admin.schema.js create mode 100644 src/validation/auth/biometric.schema.js create mode 100644 src/validation/auth/forgetPassword.schema.js create mode 100644 src/validation/auth/index.js create mode 100644 src/validation/auth/login.schema.js create mode 100644 src/validation/auth/otpVerification.schema.js create mode 100644 src/validation/auth/registration.schema.js create mode 100644 src/validation/auth/resetPaasword.schema.js create mode 100644 src/validation/auth/updatePassword.schema.js create mode 100644 src/validation/common/code.schema.js create mode 100644 src/validation/common/id.schema.js create mode 100644 src/validation/common/index.js create mode 100644 src/validation/common/search.schema.js create mode 100644 src/validation/corporate/corporateQuickAdd.schema.js create mode 100644 src/validation/corporate/createCorporate.schema.js create mode 100644 src/validation/corporate/index.js create mode 100644 src/validation/fileUpload/all.schema.js create mode 100644 src/validation/fileUpload/index.js create mode 100644 src/validation/icici/index.js create mode 100644 src/validation/icici/registration.schema.js create mode 100644 src/validation/index.js create mode 100644 yarn.lock diff --git a/ecosystem.config.json b/ecosystem.config.json new file mode 100644 index 0000000..094a7b1 --- /dev/null +++ b/ecosystem.config.json @@ -0,0 +1,16 @@ +{ + "apps": [ + { + "name": "Tanami-Backend", + "script": "src/index.js", + "instances": 1, + "autorestart": true, + "watch": false, + "time": true, + "env": { + "NODE_ENV": "production" + } + } + ] + } + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..e6ae0c3 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "Tanami-Backend", + "version": "v1.0.0", + "main": "src/index.js", + "author": "Swapnil Bendal", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "scripts": { + "start": "pm2 start ecosystem.config.json --no-daemon", + "dev": "cross-env NODE_ENV=development nodemon src/index.js", + "test": "cross-env NODE_ENV=test nodemon src/index.js" + }, + "dependencies": { + "@onesignal/node-onesignal": "^5.0.0-alpha-01", + "axios": "^1.7.5", + "bcrypt": "^5.1.1", + "compression": "^1.7.4", + "cors": "^2.8.5", + "cross-env": "^7.0.3", + "crypto": "^1.0.1", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "express-rate-limit": "^7.3.1", + "helmet": "^7.1.0", + "http-status": "^1.7.4", + "jsonwebtoken": "^9.0.2", + "moment": "^2.30.1", + "morgan": "^1.10.0", + "multer": "^1.4.5-lts.1", + "mysql2": "^3.10.2", + "nodemailer": "^6.9.14", + "request-ip": "^3.3.0", + "sequelize": "^6.37.3", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.1", + "twilio": "^5.2.2", + "winston": "^3.13.0", + "xss-clean": "^0.1.4", + "yup": "^1.4.0" + }, + "devDependencies": { + "nodemon": "^3.1.4" + } +} diff --git a/src/DTOs/index.js b/src/DTOs/index.js new file mode 100644 index 0000000..93290ed --- /dev/null +++ b/src/DTOs/index.js @@ -0,0 +1,3 @@ +module.exports = { + getAllCorporateDTO: require('./corporate/corporate.dto'), +} \ No newline at end of file diff --git a/src/api/ICICI/icici.api.js b/src/api/ICICI/icici.api.js new file mode 100644 index 0000000..f93132f --- /dev/null +++ b/src/api/ICICI/icici.api.js @@ -0,0 +1,64 @@ +const axios = require("axios"); +const config = require("../../config/config"); + +const instance = axios.create({ + baseURL: config.icici.baseURL, + headers: { + 'accept': "*", + 'Content-Type': 'text/plain', + 'apikey': config.icici.apikey, + 'x-forwarded-for': config.icici.x_forwarded_for, + 'Content-Length': 684, + } +}) + +module.exports = { + createOtp: async (encryptedData) => { + try { + const { data } = await instance.post('/api/Corporate/CIB_SV/v1/Create', encryptedData); // Assuming `url` is relative to baseURL + return data; + } catch (error) { + console.error("Error during registration API call:", error.message); // Log error message + throw error; // Throw the actual error object + } + }, + + balanceInquiry: async (encryptedData) => { + try { + const { data } = await instance.post('/api/Corporate/CIB_SV/v1/BalanceInquiry', encryptedData); // Assuming `url` is relative to baseURL + return data; + } catch (error) { + console.error("Error during Balance Inquiry API call:", error.message); // Log error message + throw error; // Throw the actual error object + } + }, + + transactionOTP: async (encryptedData) => { + try { + const { data } = await instance.post('/api/Corporate/CIB_SV/v1/TransactionOTP', encryptedData); // Assuming `url` is relative to baseURL + console.log("transactionOTP", data) + return data; + } catch (error) { + console.error("Error during transaction OTP API call:", error.message); // Log error message + throw error; // Throw the actual error object + } + }, + accountStatement: async (encryptedData) => { + try { + const {data} = await instance.post('/api/Corporate/CIB_SV/v1/AccountStatement', encryptedData); // Assuming `url` is relative to baseURL + return data; + } catch (error) { + console.error("Error during account statement API call:", error.message); // Log error message + throw error; // Throw the actual error object + } + }, + + RegistrationStatus: async (encryptedData) => { + try { + const { data } = await instance.post('registration-status', encryptedData); + return data; + } catch (error) { + throw new Error('Error during registration status API call'); + } + }, +}; diff --git a/src/api/index.js b/src/api/index.js new file mode 100644 index 0000000..d1a3298 --- /dev/null +++ b/src/api/index.js @@ -0,0 +1,3 @@ +module.exports = { + iciciApi: require('./ICICI/icici.api'), +} \ No newline at end of file diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..4b0fa9f --- /dev/null +++ b/src/app.js @@ -0,0 +1,73 @@ +const express = require('express'); +const requestIp = require('request-ip'); +const helmet = require('helmet'); +const xss = require('xss-clean'); +const compression = require('compression'); +const cors = require('cors'); +const httpStatus = require('http-status'); +const config = require('./config/config'); +const morgan = require('./config/morgan'); +const { authLimiter } = require('./middlewares/rateLimiter'); +const routes = require('./routes/v1'); +const { errorConverter, errorHandler } = require('./middlewares/error'); +const ApiError = require('./utils/handler/ApiError.handler'); +const path = require('path') + +const app = express(); + +if (config.env !== 'test') { + app.use(morgan.successHandler); + app.use(morgan.errorHandler); +} + +// Middleware to set client IP +app.use(requestIp.mw()); + +// Middleware to set dynamic Content Security Policy +app.use((req, res, next) => + helmet.contentSecurityPolicy({ + directives: { + defaultSrc: ["'self'"], + imgSrc: ["'self'", 'data:', 'https:', `http://${req.hostname}`, `https://${req.hostname}`], + }, + })(req, res, next) +); + +// parse json request body +app.use(express.json()); + +// parse urlencoded request body +app.use(express.urlencoded({ extended: true })); + +// sanitize request data +app.use(xss()); + +// gzip compression +app.use(compression()); + +// enable cors +app.use(cors()); +app.options('*', cors()); + +app.use('/public', express.static(path.join(__dirname, '../public'))); + +// limit repeated failed requests to auth endpoints +if (config.env === 'production') { + app.use('/api/v1/auth', authLimiter); +} + +// v1 api routes +app.use('/api/v1', routes); + +// send back a 404 error for any unknown api request +app.use((req, res, next) => { + next(new ApiError(httpStatus.NOT_FOUND, 'Not found')); +}); + +// convert error to ApiError, if needed +app.use(errorConverter); + +// handle error +app.use(errorHandler); + +module.exports = app; diff --git a/src/config/config.js b/src/config/config.js new file mode 100644 index 0000000..7fddcfe --- /dev/null +++ b/src/config/config.js @@ -0,0 +1,179 @@ +const dotenv = require('dotenv'); +const path = require('path'); +const yup = require('yup'); +const crypto = require('crypto'); + +dotenv.config({ path: path.join(__dirname, '../../.env') }); + +const envVarsSchema = yup.object().shape({ + NODE_ENV: yup.string().oneOf(['production', 'development', 'test']).required(), + PORT: yup.number().default(3000), + + // By Passes + BY_PASS_OTP: yup.boolean().default(true).required('by pass otp is required'), + BY_PASS_NOTIFICATION: yup.boolean().default(true).required('by pass notification is required'), + BY_PASS_EMAIL: yup.boolean().default(true).required('by pass email is required'), + + // JWT + JWT_SECRET: yup.string().required('JWT secret key is required'), + JWT_ACCESS_EXPIRATION_MINUTES: yup.number().default(30).required('minutes after which access tokens expire'), + JWT_REFRESH_EXPIRATION_DAYS: yup.number().default(30).required('days after which refresh tokens expire'), + JWT_RESET_PASSWORD_EXPIRATION_MINUTES: yup.number() + .default(10) + .required('minutes after which reset password token expires'), + JWT_VERIFY_EMAIL_EXPIRATION_MINUTES: yup.number() + .default(10) + .required('minutes after which verify email token expires'), + + // SMTP + SMTP_HOST: yup.string().nullable().required('server that will send the emails'), + SMTP_PORT: yup.number().nullable().required('port to connect to the email server'), + SMTP_USERNAME: yup.string().nullable().required('username for email server'), + SMTP_PASSWORD: yup.string().nullable().required('password for email server'), + EMAIL_FROM: yup.string().nullable().required('the from field in the emails sent by the app'), + + // SMS + TWILIO_ACCOUNT_SID: yup.string().nullable().required(), + TWILIO_AUTH_TOKEN: yup.string().nullable().required(), + TWILIO_SMS_FROM: yup.string().nullable().required(), + OTP_EXPIRE_IN_MIN: yup.number().default(5).nullable(), + + // OneSignal + ONESIGNAL_APPID: yup.string().required('app id key is required'), + ONESIGNAL_REST_APIKEY: yup.string().required('api key is required'), + ONESIGNAL_AUTHKEY: yup.string().required('auth key is required'), + + // Code + CODE_SECRET: yup.string().required('Code secret key is required'), + + // DataBase + DB_USERNAME: yup.string().required('DB Username is required'), + DB_PASSWORD: yup.string().required('DB Password is required'), + DB_DATABASE_NAME: yup.string().required('Database name is required'), + DB_HOSTNAME: yup.string().default('127.0.0.1').required('DB Hostname is required'), + DB_PORT: yup.number().default(3306).required('DB Port is required'), + + +}).noUnknown(); + +try { + const envVars = envVarsSchema.validateSync(process.env, { abortEarly: false, stripUnknown: true }); + + module.exports = { + env: envVars?.NODE_ENV, + port: envVars?.PORT, + byPassOTP: envVars?.BY_PASS_OTP, + byPassNotification: envVars?.BY_PASS_NOTIFICATION, + byPassEmail: envVars?.BY_PASS_EMAIL, + mysql: { + development: { + username: envVars.DB_USERNAME, + password: envVars.DB_PASSWORD, + database: envVars.DB_DATABASE_NAME, + host: envVars.DB_HOSTNAME, + port: envVars.DB_PORT, + dialect: "mysql", + dialectOptions: { + bigNumberStrings: true, + }, + logging: false, + define: { + freezeTableName: true, + }, + pool: { + max: 10, // Maximum number of connection in pool + min: 0, // Minimum number of connection in pool + acquire: 30000, // Maximum time in ms to acquire a connection + idle: 10000, // Maximum time in ms a connection can be idle before being released + } + }, + test: { + username: envVars.DB_USERNAME, + password: envVars.DB_PASSWORD, + database: envVars.DB_DATABASE_NAME, + host: envVars.DB_HOSTNAME, + port: envVars.DB_PORT, + dialect: "mysql", + dialectOptions: { + bigNumberStrings: true, + }, + logging: false, + define: { + freezeTableName: true, + }, + pool: { + max: 10, // Maximum number of connection in pool + min: 0, // Minimum number of connection in pool + acquire: 30000, // Maximum time in ms to acquire a connection + idle: 10000, // Maximum time in ms a connection can be idle before being released + } + }, + production: { + username: envVars.DB_USERNAME, + password: envVars.DB_PASSWORD, + database: envVars.DB_DATABASE_NAME, + host: envVars.DB_HOSTNAME, + port: envVars.DB_PORT, + dialect: "mysql", + dialectOptions: { + bigNumberStrings: true, + }, + logging: false, + define: { + freezeTableName: true, + socketPath: "/var/run/mysqld/mysqld.sock", + }, + pool: { + max: 10, // Maximum number of connection in pool + min: 0, // Minimum number of connection in pool + acquire: 30000, // Maximum time in ms to acquire a connection + idle: 10000, // Maximum time in ms a connection can be idle before being released + } + }, + }, + jwt: { + secret: envVars?.JWT_SECRET, + accessExpirationMinutes: envVars?.JWT_ACCESS_EXPIRATION_MINUTES, + refreshExpirationDays: envVars?.JWT_REFRESH_EXPIRATION_DAYS, + resetPasswordExpirationMinutes: envVars?.JWT_RESET_PASSWORD_EXPIRATION_MINUTES, + verifyEmailExpirationMinutes: envVars?.JWT_VERIFY_EMAIL_EXPIRATION_MINUTES, + }, + email: { + smtp: { + host: envVars?.SMTP_HOST, + port: envVars?.SMTP_PORT, + secure: process.env.SMTP_PORT == 465, // true for 465, false for other ports + auth: { + user: envVars?.SMTP_USERNAME, + pass: envVars?.SMTP_PASSWORD, + }, + }, + from: envVars?.EMAIL_FROM, + }, + code: { + secret: crypto.createHash('sha256').update(envVars.CODE_SECRET).digest(), + blacklist: new Set(), + }, + SMS: { + accountSid: envVars.TWILIO_ACCOUNT_SID, + authToken: envVars.TWILIO_AUTH_TOKEN, + from: envVars.TWILIO_SMS_FROM, + }, + expiryTime: { + otp_in_Min: envVars.OTP_EXPIRE_IN_MIN || 2, + }, + oneSignal: { + appID: envVars.ONESIGNAL_APPID, + userAuthKey: envVars.ONESIGNAL_AUTHKEY, + restApiKey: envVars.ONESIGNAL_REST_APIKEY, + }, + icici: { + baseURL: "https://apibankingonesandbox.icicibank.com", + apikey: "COIbAAYzt0SMosd3fFexJlk42uqnPvvu", + x_forwarded_for: "122.179.140.110" + } + + }; +} catch (error) { + throw new Error(`Config validation error: ${Array.isArray(error?.errors) ? error.errors?.join(', ') : error}`); +} diff --git a/src/config/logger.js b/src/config/logger.js new file mode 100644 index 0000000..bba9a7c --- /dev/null +++ b/src/config/logger.js @@ -0,0 +1,26 @@ +const winston = require('winston'); +const config = require('./config'); + +const enumerateErrorFormat = winston.format((info) => { + if (info instanceof Error) { + Object.assign(info, { message: info.stack }); + } + return info; +}); + +const logger = winston.createLogger({ + level: config.env === 'development' ? 'debug' : 'info', + format: winston.format.combine( + enumerateErrorFormat(), + config.env === 'development' ? winston.format.colorize() : winston.format.uncolorize(), + winston.format.splat(), + winston.format.printf(({ level, message }) => `${level}: ${message}`) + ), + transports: [ + new winston.transports.Console({ + stderrLevels: ['error'], + }), + ], +}); + +module.exports = logger; diff --git a/src/config/morgan.js b/src/config/morgan.js new file mode 100644 index 0000000..32d650f --- /dev/null +++ b/src/config/morgan.js @@ -0,0 +1,33 @@ +const morgan = require('morgan'); +const config = require('./config'); +const logger = require('./logger'); + +// Create a custom token for client IP +morgan.token('clientIp', (req) => req.clientIp || ''); + +// Custom token for error message +morgan.token('message', (req, res) => res.locals.errorMessage || ''); + +// Function to get IP format based on environment +const getIpFormat = () => (config.env === 'production' ? ':clientIp - ' : ''); + +// Define the response formats using morgan tokens +const successResponseFormat = `${getIpFormat()}:method :url :status - :response-time ms`; +const errorResponseFormat = `${getIpFormat()}:method :url :status - :response-time ms - message: :message`; + +// Success handler (for requests with status codes below 400) +const successHandler = morgan(successResponseFormat, { + skip: (req, res) => res.statusCode >= 400, + stream: { write: (message) => logger.info(message.trim()) }, +}); + +// Error handler (for requests with status codes 400 and above) +const errorHandler = morgan(errorResponseFormat, { + skip: (req, res) => res.statusCode < 400, + stream: { write: (message) => logger.error(message.trim()) }, +}); + +module.exports = { + successHandler, + errorHandler, +}; diff --git a/src/config/nodemailerConfig.js b/src/config/nodemailerConfig.js new file mode 100644 index 0000000..6ada5a2 --- /dev/null +++ b/src/config/nodemailerConfig.js @@ -0,0 +1,7 @@ +const nodemailer = require('nodemailer'); +const config = require('./config'); + +const transporter = nodemailer.createTransport(config.email.smtp); + +module.exports = { transporter } + diff --git a/src/config/oneSignal.config.js b/src/config/oneSignal.config.js new file mode 100644 index 0000000..0d77088 --- /dev/null +++ b/src/config/oneSignal.config.js @@ -0,0 +1,10 @@ +const OneSignal = require("@onesignal/node-onesignal"); +const config = require("./config"); +const configuration = OneSignal.createConfiguration({ + userAuthKey: config.oneSignal.userAuthKey, // Your User Auth Key + restApiKey: config.oneSignal.restApiKey, // Your REST API Key +}); + +const client = new OneSignal.DefaultApi(configuration); + +module.exports = client; diff --git a/src/config/roles.js b/src/config/roles.js new file mode 100644 index 0000000..dcf42c7 --- /dev/null +++ b/src/config/roles.js @@ -0,0 +1,12 @@ +const allRoles = { + user: [], + admin: ['getUsers', 'manageUsers'], +}; + +const roles = Object.keys(allRoles); +const roleRights = new Map(Object.entries(allRoles)); + +module.exports = { + roles, + roleRights, +}; diff --git a/src/config/tokens.js b/src/config/tokens.js new file mode 100644 index 0000000..77a9976 --- /dev/null +++ b/src/config/tokens.js @@ -0,0 +1,10 @@ +const tokenTypes = { + ACCESS: 'access', + REFRESH: 'refresh', + RESET_PASSWORD: 'resetPassword', + VERIFY_EMAIL: 'verifyEmail', +}; + +module.exports = { + tokenTypes, +}; diff --git a/src/config/twilioClient.js b/src/config/twilioClient.js new file mode 100644 index 0000000..acf0582 --- /dev/null +++ b/src/config/twilioClient.js @@ -0,0 +1,10 @@ + +const twilio = require('twilio'); +const config = require('./config'); + +const accountSid = config.SMS.accountSid; +const authToken = config.SMS.authToken; + +const twilioClient = twilio(accountSid, authToken); + +module.exports = twilioClient; \ No newline at end of file diff --git a/src/controllers/icici/icicibank.controller.js b/src/controllers/icici/icicibank.controller.js new file mode 100644 index 0000000..e0551fe --- /dev/null +++ b/src/controllers/icici/icicibank.controller.js @@ -0,0 +1,115 @@ +const { AsyncHandler } = require('../../utils/handler/Async.handler'); +const ApiError = require('../../utils/handler/ApiError.handler'); +const ApiResponse = require('../../utils/handler/ApiResponse.handler'); +const { cryptoService } = require('../../services'); +const { iciciApi } = require('../../api'); + +module.exports = { + createOTP: AsyncHandler(async (req, res) => { + try { + const jsonData = { + "AGGRNAME": "CIBTESTING", + "AGGRID": "TXBCIBTEST001", + "CORPID": "TXBCORP1", + "USERID": "USER1", + "URN": "TESTING123", + "UNIQUEID": "ABC125" + } + const encryptedData = await cryptoService.encryptWithPublicKey(jsonData) + const result = await iciciApi.createOtp(encryptedData) + const decryptedData = await cryptoService.decryptWithPrivateKey(result); + res.status(200).json(new ApiResponse(200, decryptedData, "Registration successful")); + } catch (error) { + throw new ApiError(500, "Registration failed"); + } + }), + + balanceInquiry: AsyncHandler(async (req, res) => { + try { + const jsonData = { + "AGGRID": "TXBCIBTEST001", + "CORPID": "TXBCORP1", + "USERID": "USER1", + "URN": "TESTING123", + "ACCOUNTNO": "010205001809" + } + const encryptedData = await cryptoService.encryptWithPublicKey(jsonData) + const result = await iciciApi.balanceInquiry(encryptedData) + const decryptedData = await cryptoService.decryptWithPrivateKey(result); + res.status(200).json(new ApiResponse(200, decryptedData, "Balance Inquiry successful")); + } catch (error) { + throw new ApiError(500, "Balance Inquiry failed"); + } + }), + + transactionOTP: AsyncHandler(async (req, res) => { + try { + const jsonData = { + "AGGRNAME": "CIBTESTING", + "AGGRID": "TXBCIBTEST001", + "CORPID": "TXBCORP1", + "USERID": "USER1", + "URN": "TESTING123", + "UNIQUEID": "ABC126", + "DEBITACC": "010205001809", + "CREDITACC": "000451000301", + "IFSC": "ICIC0000011", + "AMOUNT": "96.74", + "CURRENCY": "INR", + "TXNTYPE": "TPA", + "OTP": "580601", + "PAYEENAME": "WDI", + "REMARKS": "Test" + } + const encryptedData = await cryptoService.encryptWithPublicKey(jsonData) + const result = await iciciApi.transactionOTP(encryptedData) + const decryptedData = await cryptoService.decryptWithPrivateKey(result); + res.status(200).json(new ApiResponse(200, decryptedData, "Transaction OTP successful")); + } catch (error) { + throw new ApiError(500, "Transaction OTP failed"); + } + }), + + accountStatement: AsyncHandler(async (req, res) => { + try { + const jsonData = { + "AGGRID": "TXBCIBTEST001", + "CORPID": "TXBCORP1", + "USERID": "USER1", + "ACCOUNTNO": "010205001809", + "FROMDATE": "01-01-2016", + "TODATE": "30-12-2016", + "URN": "TESTING123" + } + + const encryptedData = await cryptoService.encryptWithPublicKey(jsonData) + const result = await iciciApi.accountStatement(encryptedData) + console.log("result", result) + + const decryptEncryptedKey = await cryptoService.decryptKey(result.encryptedKey) + + const decodedData = await cryptoService.base64Decode(result.encryptedData); + const getIV = await cryptoService.getIV(decodedData); + const statement = await cryptoService.decryptData(decodedData, decryptEncryptedKey, getIV) + res.status(200).json(new ApiResponse(200, statement, "Account Statement Data Fetched Successfully")); + } catch (error) { + throw new ApiError(500, "Account Statement Data failed"); + } + }), + + RegistrationStatus: AsyncHandler(async (req, res) => { + try { + const jsonData = { + AGGRNAME: "CIBTESTING", + AGGRID: "TXBCIBTEST001", + CORPID: "TXBCORP1", + USERID: "USER1", + URN: "TESTING123" + }; + const data = await registrationService.checkRegistrationStatus(); + res.status(200).json(new ApiResponse(200, data, "Registration status retrieved")); + } catch (error) { + throw new ApiError(500, "Failed to retrieve registration status"); + } + }), +}; diff --git a/src/controllers/index.js b/src/controllers/index.js new file mode 100644 index 0000000..d13f11c --- /dev/null +++ b/src/controllers/index.js @@ -0,0 +1,3 @@ +module.exports = { + iciciBankController: require('./icici/icicibank.controller') +} \ No newline at end of file diff --git a/src/data/data.json b/src/data/data.json new file mode 100644 index 0000000..f3d69aa --- /dev/null +++ b/src/data/data.json @@ -0,0 +1,106 @@ +{ + "iamType": [ + { + "principalTypeName": "OptifiiAdmin" + }, + { + "principalTypeName": "CorporateAdmin" + }, + { + "principalTypeName": "User" + } + ], + "iamSource": [ + { + "sourceName": "Web" + }, + { + "sourceName": "Mobile" + } + ], + "administrator": { + "firstName": "Vinay", + "lastName": "Agarwal", + "ISDcode": "+91", + "mobileNumber": "88888888888", + "emailAddress": "admin@optifii.com", + "password": "Admin@123", + "principalType": "OptifiiAdmin", + "principalSource": "Web" + }, + "corporate_status": [ + { + "status": "Requested" + }, + { + "status": "Submitted" + }, + { + "status": "Registerd" + }, + { + "status": "Approved" + }, + { + "status": "Rejected" + } + ], + "corporate_type": [ + { + "corporate_type": "C Corporation (C Corp)" + }, + { + "corporate_type": "S Corporation (S Corp)" + }, + { + "corporate_type": "Limited Liability Company (LLC)" + }, + { + "corporate_type": "Nonprofit Corporation" + }, + { + "corporate_type": "Benefit Corporation (B Corp)" + }, + { + "corporate_type": "Professional Corporation (PC)" + }, + { + "corporate_type": "Cooperative (Co-op)" + } + ], + "industry": [ + { + "industry_name": "Agriculture and Natural Resources" + }, + { + "industry_name": "Manufacturing" + }, + { + "industry_name": "Construction and Real Estate" + }, + { + "industry_name": "Services" + }, + { + "industry_name": "Technology" + }, + { + "industry_name": "Finance and Insurance" + }, + { + "industry_name": "Media and Entertainment" + }, + { + "industry_name": "Energy and Utilities" + }, + { + "industry_name": "Professional Services" + }, + { + "industry_name": "Nonprofit and Community Services" + }, + { + "industry_name": "Emerging Industries" + } + ] +} diff --git a/src/docs/swaggerDef.js b/src/docs/swaggerDef.js new file mode 100644 index 0000000..e75854a --- /dev/null +++ b/src/docs/swaggerDef.js @@ -0,0 +1,18 @@ +const { version } = require('../../package.json'); +const config = require('../config/config'); + +const swaggerDef = { + openapi: '3.0.0', + info: { + title: 'Tanami Backend API documentation', + version, + description: 'Tanami Backend API documentation', + }, + servers: [ + { + url: `http://localhost:${config.port}/v1`, + }, + ], +}; + +module.exports = swaggerDef; diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..d53d7ad --- /dev/null +++ b/src/index.js @@ -0,0 +1,51 @@ +const app = require('./app'); +const config = require('./config/config'); +const logger = require('./config/logger'); +const db = require('./models'); +// const seed = require('./seed'); + +let server; + +db.sequelize + .sync({ force: config.env === 'test' }) + .then(() => { + logger.info('Connected to MySQL'); + // seed(db) + server = app.listen(config.port, () => { + logger.info(`Server listening on port ${config.port}`) + logger.info(`Enviorment :- ${config.env}`); + logger.info(`Is OTP by pass :- ${config.byPassOTP}`); + logger.info(`Is Notification by pass :- ${config.byPassNotification}`); + logger.info(`Is Email by pass :- ${config.byPassEmail}`); + }); + }) + .catch((error) => { + logger.error('Error connecting to MySQL:', error); + process.exit(1); + }); + +const exitHandler = () => { + if (server) { + server.close(() => { + logger.info('Server closed'); + process.exit(1); + }); + } else { + process.exit(1); + } +}; + +const unexpectedErrorHandler = (error) => { + logger.error(error); + exitHandler(); +}; + +process.on('uncaughtException', unexpectedErrorHandler); +process.on('unhandledRejection', unexpectedErrorHandler); + +process.on('SIGTERM', () => { + logger.info('SIGTERM received'); + if (server) { + server.close(); + } +}); diff --git a/src/keys/certificate.pem b/src/keys/certificate.pem new file mode 100644 index 0000000..abc9a2b --- /dev/null +++ b/src/keys/certificate.pem @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +MIIFhDCCA2wCCQCIqfcsomoC1jANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCSU4xF +DASBgNV +BAgMC01BSEFSQVNIVFJBMQ8wDQYDVQQHDAZNVU1CQUkxGDAWBgNVBAoMD0lDSUN +JIEJhbmsgTHRk +LjEMMAoGA1UECwwDQ0lCMSUwIwYDVQQDDBx3d3cuY2libmV4dGFwaS5pY2ljaWJhbmsuY +29tMB4X +DTE3MDQxMzA3MTkyOVoXDTIyMDQxMjA3MTkyOVowgYMxCzAJBgNVBAYTAklOMRQwEgY +DVQQIDAtN +QUhBUkFTSFRSQTEPMA0GA1UEBwwGTVVNQkFJMRgwFgYDVQQKDA9JQ0lDSSBCYW5rI +Ex0ZC4xDDAK +BgNVBAsMA0NJQjElMCMGA1UEAwwcd3d3LmNpYm5leHRhcGkuaWNpY2liYW5rLmNvbTCC +AiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAM+en2ErEsETmfoZJjf3I5DIc8KAt6dv/ZkKYHcpli1 +g +yLFjJNbZnyk4Um7UaKvU0fpqnsLboapXKR0iHFp4/7SR9kTh4FfvFrrp2pKmQd8f/Rf6OPk2/48i +X7sCs0nl8IZYMqe1Tt1YAMFPJjPIH/ERx3vnWYhgHUmRGJqjHfo4NeNR0IarF3HAYX4hh6K0L +aAQ +hUoq6SuWyWf9m9qzHRHpWq4eJRsbhPYLaTtt8XS+vPpBjFjfQreDtgWdIXwKuHq8EOS/KxBif +ThC +tEBMGZUSYZBoldq1kdaakkt5FaXhe+g0FWrLcxalaSS4bHK0QCv1Lbh3tcPetCO3XyR1Jj28SL ++5 +gYm464jmjMGURJwocWUhuNd0qAKt8bMv9NCDgKiWSmAlzeznRYeNaay2ckg5aB5tNO5l/8pU +h8Ew +qLyKECFnCoNvBlcaoJIvZ0sprQO+dHzggT/Q9wl0XRFUkPh4SFGHIiqldy6VgA6I7uVWb7ve1Y3 +P +4yhlfTDV/Hr4ZL4gTFVrorS1a4Tqap38iqHnfM3djwgwbnzv0TJZCywZ5ED8MRDmub6W4jNYMV +ar +uG1gLVf7gE2sUY/dgTRu1Hdw3/YlOY9XpQebBP37RD3+Up+oEYxjPe04Cy4rTFx9/8SluuBPvw +NH +WVmHkv1ULNHum0VQ3kej17jbEeO+FftJAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAMGX2 +dKuXsGj +ujhKxZOFzo8A0QKu+nsw+pFtiJ5KjyOR1vW9pOdG7roJJGr6cU5fUDlUpYDDVIvPiVbPYgWLkV +e3 +7+tpM8T77ZYSXdO7G9hhU8uw2pcRHiQMlDotV/RcTGZHyVVaw7TJty3xMH2j0/FIHejcFaYXZY +QB +A5+zKc7PBsvwn/KQgJ9R4BTqmdWeca1r0+iBXGq1iRg4IGePf0lIc+80AUneC1ceC07RfvI0PJp +k +LVTkDCXdNK7QtG/cIqjdZ1jtB+ne7cwtksw1ewu5dE3BFNmqdT3DmKHAupTc2ILSup2w/JEEep +MI +DHO8GvqR0dUXS5xCcXNKwXUMiLPYA56mRKoST5+e2RO5WtVQMHiizEF5iID+WjyXNlVtqM +arEjih +Z0+/vkABp/Q3AfKs3rtaXxU4crt+RLaaldG/dBXOoUDTpaNR+ktUkNmEPTe9zc7pwwRDC2zNylt +4 +FnhNP2b2t+RLuP+smAROVaXA1owpte3zeh7aiUe02Y6udEzVrKCAvRUiCKoCDH9N101k3lzC +Fy80 +rRquHZ7ZZmUrX4DksuPnSuLILR5ss6UkQTZbg7HXtMN2lDTgPjO2UMCjqI+5gPGTqdld4XWD +TEW0 +xdyhJiEgATeqQllbn47B7C7603ltWFpoInafn2NwxBW89wv938bMKpxFxmQcseGH +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/keys/public_key.pem b/src/keys/public_key.pem new file mode 100644 index 0000000..df2291f --- /dev/null +++ b/src/keys/public_key.pem @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAz56fYSsSwROZ+hkmN/cj +kMhzwoC3p2/9mQpgdymWLWDIsWMk1tmfKThSbtRoq9TR+mqewtuhqlcpHSIcWnj/ +tJH2ROHgV+8WuunakqZB3x/9F/o4+Tb/jyJfuwKzSeXwhlgyp7VO3VgAwU8mM8gf +8RHHe+dZiGAdSZEYmqMd+jg141HQhqsXccBhfiGHorQtoBCFSirpK5bJZ/2b2rMd +Eelarh4lGxuE9gtpO23xdL68+kGMWN9Ct4O2BZ0hfAq4erwQ5L8rEGJ9OEK0QEwZ +lRJhkGiV2rWR1pqSS3kVpeF76DQVastzFqVpJLhscrRAK/UtuHe1w960I7dfJHUm +PbxIv7mBibjriOaMwZREnChxZSG413SoAq3xsy/00IOAqJZKYCXN7OdFh41prLZy +SDloHm007mX/ylSHwTCovIoQIWcKg28GVxqgki9nSymtA750fOCBP9D3CXRdEVSQ ++HhIUYciKqV3LpWADoju5VZvu97Vjc/jKGV9MNX8evhkviBMVWuitLVrhOpqnfyK +oed8zd2PCDBufO/RMlkLLBnkQPwxEOa5vpbiM1gxVqu4bWAtV/uATaxRj92BNG7U +d3Df9iU5j1elB5sE/ftEPf5Sn6gRjGM97TgLLitMXH3/xKW64E+/A0dZWYeS/VQs +0e6bRVDeR6PXuNsR474V+0kCAwEAAQ== +-----END PUBLIC KEY----- diff --git a/src/keys/rsa_private_key.pem b/src/keys/rsa_private_key.pem new file mode 100644 index 0000000..4c7c96d --- /dev/null +++ b/src/keys/rsa_private_key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKQIBAAKCAgEAqj4v2DMCY3kl5cedsFzM9/jjiYfXbp5PiaXrtGfl9o1kNej4 +YGg6+uV4sLclxT66n2mknE7hKLRmMRbjpN3d2NU+KzVx0CKEmJ2RKtCYsTw0iCaA +b2D4hDYZBhdzyBbqdhCgdUhzexFuTtlXlT8U5fZvv+nj8xXrm5Q6z8AuQy/q2AN1 +blGaifSbebPgdyhJ3DqgBSP0x67pvyEVWOVerhMw6L6eqfnDHEvaEopynEpm8eQx +kUxroVbERyFfGP/poOb2LSlUqvhK4LOR3Zt1YW/KdcJ+a/8W2zSHyhHVuHwVb4ke +LYC2IdYpcZuwyxN6PX4/k9mLcQbhGUerD+c59U/DhXnOjyHLMc6HtfO4MO5v6DbC +XsZca5qjqBabKJbrpcGZrEQ+6ECriajYySfgUbxppytSBhcIjSzFPKyM4oUgEOFU +LVmoVXo1UjuhaR7Q7NhDEqE4lg67dtGrCTZ/KAITgLhU9CIS6qRes4pO7S/lXfRE +yBaYepcaLsS66dnq9zjXNnHY/L6zwCuyzjt2Im34TXDYfjxkKnGLDvLN15ZGt6Ji +VAFh4Tb2hCF1tWs97VwaZJq/czIBt/jmabGBNJ1wZ2yFshTfeCnvtPlqO6VZeNP7 +HqoRF7rVPuePkRiff8E6s2bxisF2pt+2t/swNlZj4pHEoRiEhdJavWLuz+0CAwEA +AQKCAgAUB1NtKdkk106qWSD36/8QSGeKmWDyymy8mrjfhV60cj+BKSq5euG/fUpE +7hMjQMVHdnAPlKcgORMRwOngzlpohXP2NOgyLrFvXBBFW3uvVFAw2WjAUcYDFfM9 +OHqeZnXIlJ2wFqlBaBRUcfUAIccFZAgTKcLv6RsKN3bw1KEMtgE4zzVcWHzoMI8v +Ewa8NhD0eDA10pxcdrtYyV1f00Jfk/Hr2+tCP5hhBpp+Fmwz73vrhud++uDpvxHB +9Y7g29DCZZG+T+++Wo5Cn9WwHvdBEpwc3Rgu//iSKvyzvQPqG60Q7W6Pt2YWFoJT +M5gp2B2ISQdVT2F8l2zZoskhCpjSjqMXJxwgg/jp/uXLaTEYNtKCbMM1DSrg1VnQ +78OyhBV7TJBq+hsAwPeuxiaujSv+LjxbeBWHBUZa2Ru2bcN22zzbtAySrTH8TtOw +1UeTkz0lG3alPW1alAYcZF7nNTOv7VAEUhFBgIKF96jgSzUDpkAVClW0gmAwng2u +8zw+Hqtws/UQgeMxoE+Fs+wlwq/GK/219TMoARpdYdgN2l09q9dFZ2d0A2mzvAD1 +aUTdgnOrfcel/3IfIBXt8PN51JlASmp7XMVWjVolQ6iG90+zKwpzlZX3XoupyUZj +ChaoR0kwk4GEQgwqlLHTJcrmbDvbJxMmi6f0HFK4s/D19c8xuQKCAQEA0x/mu3I4 +dRI46Cgx8BEKH9Isp2t1pCsn4Ai/GhwASRRryi9ZO0pQsR06xayulE1zTSPIg/Mq +wT4Yo/e9QZrRGvhsMSFCU5jHhDHgr77IRoSibZ5C4v99P9Sbi3b3wGsxkiYuttDE +exBy+9HSpRgJxDdXZGEOMSl3+IF/VsZe2eL5JArWBC4XZU/Lm4C3C/HlAA9aVQVb +U+rjlJcL0T9iFzjDiJdzwVxK3oDRVpxyh/hHmD47DZmb7u8Ea1VjIlntrjKymWta +Z/6tPJ81oJftQhSexRHZPFy+Wtm2xfPkENEfsVxtwQQ6Hg7bk9Iwme8Oj/pKFLpI +4W5l4YIqJWX0WQKCAQEAzm3BhEFXOkAy89f9PLx6o1RFqCutx6Silt2rv/SpB4Ju +VWvRLdPZxqQbHQ/5enZ6MEUTCoNzaM2uGbz4TP3718hWW7Sw6QlN1iOYS3eODNNQ +YZIz+IpLJ9hbrWua7LS1Ypb7IO6F+F8lEbue9evyWD2EderA8NckWGEv5JTiBuTT +sXsKNhRuBOBwht7nXwL8s1DEdkok5mLmFlqtIYDpQRm3N9IVa40wn2g+8ww8C7tR +uygDO4PvPnTBhMVEz78MtVOk3MZYjIHhGsJR6iTB0zc3ze6gaVQ3eigyA1Ii/AUy +fke/cPiw30oVRJHnyZFTo06sNXjqtlc+DvSNNIPVtQKCAQEAg/a4vgmTCHovX81g +CXJdJa61gqBElCz1a6+L48IE26kMBwC5gbnd3hcrGUvqg4A1xc3ME832t3sc48CC +Z3NhqL4Gwl7Lmn0wmIykqLVTceCNtn7pyAFyRGecIfxmt7tI7NU49cRgS5vog0aP +p+nykNcWpQOVX11QQ+CNu6uatg6NM94iD9LPhN/voG8/+xNj1DnEeMg0Yau8PLB9 +DnnT0jgE4GfqTr5lfdZ/AugfHqYt+hdLyiBtu1djJ8PjhyE201+VCxhzFfW2SuIp +HwxXnKpO41dYtcYypY7YE7tynqBYcwAXCkKeIROgZDFJd65ZJ92GWJZn36ClxeMa +fO3RYQKCAQEAoQFiKnF8Q2bHVwFj9vdbAAE+w0guJsT2O41x5CpDnCPTQrTxVjki +ZpigvS40e5vk+bkmfNDCN0AVRuXpFMQUpd0P3j80rM4g86CXrGT3WnGHBFMwTe4v +aEiMWNrQ30ajIt53yNvBilNLamVYOp9pSgHRStdq3W4wXu6OmE63bIEVzBwXfs64 +cP1NRyScebKuvn2Efm6eEUOaCl13I+aUB76y9MrbAiQBhJOeZZtpSg00VjGDM+xX +sfMG7TOf1BlDJDq1H61ka1Lx7BkcIu/Abaln0SsJ2p1hF9o6B/UMbFzxYSU84DRY +YBA8Pls+2iyLe5hlIN/K0aWCNc/wQsGA8QKCAQB4Yg8kQ/Wz5oX0dmMHC/ygXKmi +aJlXigCWzIwmwrp4uVeGeYh7WTzIyt42aYvbKa7liq0NyFiKBJYUuwmqDaHAu5Il +R4CdaWFu8hD5rN2qYwGpUIJdVUwsR9g6bebDYg8TEknSFzLrDwgxKRCmcEnwsmho +k2GnzUzIb+by/qNTKCByExEoYSsqo/V6oTmFmNp1tp3VEvZvQmy4Px7gehmBxbmx +ONDFz27NOwspEE+TsbIds9W5NmBCIUsgGMiK3bV5F3dwy649Vt0cpyGXkxr8ksfX +3visuVX+95IPVyoY6M+J/p2xcYhJwci1A7Cexw7QcalcmfOm8x8qPtnhH6Lk +-----END RSA PRIVATE KEY----- diff --git a/src/middlewares/auth.js b/src/middlewares/auth.js new file mode 100644 index 0000000..6d0031b --- /dev/null +++ b/src/middlewares/auth.js @@ -0,0 +1,39 @@ +const jwt = require('jsonwebtoken'); +const httpStatus = require('http-status'); +const { roleRights } = require('../config/roles'); // Replace with your actual JWT secret configuration +const ApiError = require('../utils/handler/ApiError.handler'); +const config = require('../config/config'); + +const verifyCallback = async (req, resolve, reject, requiredRights) => { + const token = req.header("x-auth-token"); // Assuming the token is passed in the Authorization header + if (!token) { + return reject(new ApiError(httpStatus.UNAUTHORIZED, 'Please authenticate')); + } + + try { + const decoded = jwt.verify(token, config.jwt.secret); + req.user = decoded + + if (requiredRights.length) { + const userRights = roleRights.get(req.user.role); + const hasRequiredRights = requiredRights.every((requiredRight) => userRights.includes(requiredRight)); + if (!hasRequiredRights && req.params.userId !== req.user.id) { + return reject(new ApiError(httpStatus.FORBIDDEN, 'Forbidden')); + } + } + + resolve(); + } catch (err) { + return reject(new ApiError(httpStatus.FORBIDDEN, 'Please authenticate')); + } +}; + +const auth = (...requiredRights) => async (req, res, next) => { + return new Promise((resolve, reject) => { + verifyCallback(req, resolve, reject, requiredRights); + }) + .then(() => next()) + .catch((err) => next(err)); +}; + +module.exports = auth; diff --git a/src/middlewares/code.js b/src/middlewares/code.js new file mode 100644 index 0000000..475b656 --- /dev/null +++ b/src/middlewares/code.js @@ -0,0 +1,11 @@ +const { decryptUserId } = require("../services/code/code.service"); +const ApiError = require("../utils/handler/ApiError.handler") + +const code = (err, req, res, next) => { + const code = req.header("x-auth-code"); + if (!code) { throw new ApiError(400, "Code is Required") } + req.corporate_code = decryptUserId(code) + next() +} + +module.exports = code \ No newline at end of file diff --git a/src/middlewares/error.js b/src/middlewares/error.js new file mode 100644 index 0000000..945facb --- /dev/null +++ b/src/middlewares/error.js @@ -0,0 +1,55 @@ +const { UniqueConstraintError, BaseError, ValidationError } = require("sequelize"); +const ApiError = require("../utils/handler/ApiError.handler"); +const config = require("../config/config"); +const httpStatus = require("http-status"); +const logger = require("../config/logger"); +const multer = require("multer"); + +const errorConverter = (err, req, res, next) => { + let error = err; + + if (error instanceof multer.MulterError) { + // Handle Multer errors + error = new ApiError(httpStatus.BAD_REQUEST, error.message, error, true, err.stack); + } else if (error instanceof ValidationError || error instanceof UniqueConstraintError) { + // Handle Sequelize validation and unique constraint errors + const messages = error.errors.map(e => e.message); + error = new ApiError(httpStatus.BAD_REQUEST, messages.join(", "), messages, true, err.stack); + } else if (!(error instanceof ApiError)) { + // Handle other errors + const statusCode = + error.statusCode || error instanceof BaseError ? httpStatus.BAD_REQUEST : httpStatus.INTERNAL_SERVER_ERROR; + const message = error.message || httpStatus[statusCode]; + error = new ApiError(statusCode, message, error, false, err.stack); + } + + next(error); +}; + +// eslint-disable-next-line no-unused-vars +const errorHandler = (err, req, res, next) => { + let { statusCode, message } = err; + if (config.env === 'production' && !err.isOperational) { + statusCode = httpStatus.INTERNAL_SERVER_ERROR; + message = httpStatus[httpStatus.INTERNAL_SERVER_ERROR]; + } + + res.locals.errorMessage = err.message; + + const response = { + code: statusCode, + message, + ...(config.env === 'development' && { stack: err.stack }), + }; + + if (config.env === 'development') { + logger.error(err); + } + + res.status(statusCode).send(response); +}; + +module.exports = { + errorConverter, + errorHandler, +}; diff --git a/src/middlewares/rateLimiter.js b/src/middlewares/rateLimiter.js new file mode 100644 index 0000000..419cce1 --- /dev/null +++ b/src/middlewares/rateLimiter.js @@ -0,0 +1,11 @@ +const { default: rateLimit } = require('express-rate-limit'); + +const authLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 100, + skipSuccessfulRequests: true, +}); + +module.exports = { + authLimiter, +}; diff --git a/src/middlewares/storage.js b/src/middlewares/storage.js new file mode 100644 index 0000000..8c184c3 --- /dev/null +++ b/src/middlewares/storage.js @@ -0,0 +1,92 @@ +const multer = require('multer'); +const fs = require('fs') +const path = require('path'); +const ApiError = require('../utils/handler/ApiError.handler'); +const maxFileSize = 10 * 1024 * 1024; // 10 MB (in bytes) +const allowedFileTypes = [ + "image/jpeg", + "image/png", + "image/gif", + "application/pdf", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "video/mp4", + "video/x-msvideo", + "video/x-matroska", + "video/webm", + "video/ogg", + "video/quicktime" +]; + +// Define the storage engine function with parameters +const uploader = (folderName) => multer.diskStorage({ + destination: function (req, file, cb) { + // Check if the 'public' directory exists, and create it if it doesn't + if (!fs.existsSync("public")) { + try { + fs.mkdirSync("public"); + } catch (err) { + return cb(err); + } + } + + // Handle directory structure based on corporate_code if available + let directoryPath = `public`; + if (req.corporate_code) { + directoryPath += `/${req.corporate_code}`; + } + directoryPath += `/${folderName}`; + + // Check if the directory exists, create it if it doesn't + if (!fs.existsSync(directoryPath)) { + try { + fs.mkdirSync(directoryPath, { recursive: true }); + } catch (err) { + return cb(err); + } + } + + cb(null, directoryPath); + }, + filename: function (req, file, cb) { + const transformedFilename = file.originalname + .trim() + .toLowerCase() + .replace(/[^a-z\d.]+/g, "_") + .replace(/_+/g, "_") + .replace(/\.[^.]+$/, "") + .replace(/\./g, "_") + .replace(/^_|_$/g, ""); + + cb( + null, + transformedFilename + path.extname(file.originalname) + ); + }, +}); + + +// Define the file filter function with parameters +const fileFilter = (allowedTypes = allowedFileTypes) => function (req, file, cb) { + if (allowedTypes.includes(file.mimetype)) { + cb(null, true); // Allow the file + } else { + cb(new ApiError(400, "File type not allowed")); // Reject the file + } +}; + +// Set up the multer storage with parameters and file filter +const storage = (folderName, allowedTypes, options = {}) => multer({ + storage: uploader(folderName || "asset"), + limits: { + fileSize: options.fileSize || maxFileSize, + }, + fileFilter: fileFilter(allowedTypes), + ...options, // Merge additional options +}); + +// Example usage: +// const upload = storage("document", allowedFileTypes, { fileSize: 5 * 1024 * 1024, preservePath: true }); +// You can then use `upload` as middleware in your routes. + +module.exports = storage; diff --git a/src/middlewares/validate.js b/src/middlewares/validate.js new file mode 100644 index 0000000..6b7766a --- /dev/null +++ b/src/middlewares/validate.js @@ -0,0 +1,27 @@ +const httpStatus = require("http-status"); +const ApiError = require("../utils/handler/ApiError.handler"); +const pick = require("../utils/handler/pick.handler"); + +const validate = (schema) => (req, res, next) => { + const validSchema = pick(schema, ['params', 'query', 'body', 'file', 'files']); + const object = pick(req, Object.keys(validSchema)); + + const promises = Object.keys(validSchema).map((key) => + validSchema[key].validate(object[key], { abortEarly: false }) + ); + + Promise.all(promises) + .then((validatedValues) => { + validatedValues.forEach((value, index) => { + const key = Object.keys(validSchema)[index]; + req[key] = value; + }); + next(); + }) + .catch((err) => { + const errorMessage = err.inner.map((detail) => detail.message).join(', '); + next(new ApiError(httpStatus.BAD_REQUEST, errorMessage)); + }); +}; + +module.exports = validate; diff --git a/src/models/index.js b/src/models/index.js new file mode 100644 index 0000000..3bc58f0 --- /dev/null +++ b/src/models/index.js @@ -0,0 +1,39 @@ +"use strict"; + +const { Sequelize } = require("sequelize"); +const config = require("../config/config"); +const logger = require("../config/logger"); + +// Initialize Sequelize instance +const sequelize = new Sequelize( + config.mysql[config.env].database, + config.mysql[config.env].username, + config.mysql[config.env].password, + config.mysql[config.env] +); + +// Test database connection +sequelize + .authenticate() + .then(() => logger.info("Connection has been established successfully.")) + .catch((error) => logger.error("Unable to connect to the database: ", error)); + +// Load models +const db = {}; + +//main models +// db.token = require('./main/token.model')(sequelize); + +// Handle model associations +(async () => { + for (const modelName of Object.keys(db)) { + if (db[modelName].associate) { + await db[modelName].associate(db); + } + } +})(); + +db.sequelize = sequelize; +db.Sequelize = Sequelize; + +module.exports = db; diff --git a/src/routes/v1/icici/index.js b/src/routes/v1/icici/index.js new file mode 100644 index 0000000..73d0108 --- /dev/null +++ b/src/routes/v1/icici/index.js @@ -0,0 +1,5 @@ +const iciciRoutes = require('express').Router() + +iciciRoutes.use('/', require('./user.routes')) + +module.exports = iciciRoutes \ No newline at end of file diff --git a/src/routes/v1/icici/user.routes.js b/src/routes/v1/icici/user.routes.js new file mode 100644 index 0000000..c8d16d0 --- /dev/null +++ b/src/routes/v1/icici/user.routes.js @@ -0,0 +1,10 @@ +const { iciciBankController } = require('../../../controllers/index') + +const userRoutes = require('express').Router(); + +userRoutes.route('/create-otp').post(iciciBankController.createOTP); +userRoutes.route('/balance-inquiry').post(iciciBankController.balanceInquiry); +userRoutes.route('/transaction-otp').post(iciciBankController.transactionOTP); +userRoutes.route('/account-statement').post(iciciBankController.accountStatement); + +module.exports = userRoutes; diff --git a/src/routes/v1/index.js b/src/routes/v1/index.js new file mode 100644 index 0000000..e7fc8fc --- /dev/null +++ b/src/routes/v1/index.js @@ -0,0 +1,27 @@ +const express = require('express');; +const config = require('../../config/config'); + +const router = express.Router(); + +const defaultRoutes = [ + { + path: '/icici', + route: require('./icici'), + }, +]; + +const devRoutes = [ + // routes available only in development mode +]; + +defaultRoutes.forEach((route) => { + router.use(route.path, route.route); +}); +/* istanbul ignore next */ +if (config.env === 'development') { + devRoutes.forEach((route) => { + router.use(route.path, route.route); + }); +} + +module.exports = router; diff --git a/src/services/IAM/iam_principal.service.js b/src/services/IAM/iam_principal.service.js new file mode 100644 index 0000000..c18f18a --- /dev/null +++ b/src/services/IAM/iam_principal.service.js @@ -0,0 +1,60 @@ +const db = require("../../models"); +const iamConstant = require("../../utils/constant/iam.constant"); +const ApiError = require("../../utils/handler/ApiError.handler"); + +module.exports = { + create: async (data) => await db.iam_principal.create(data), + createInvestor: async (data) => { + const source = await db.iam_principal_source.findOne({ where: { sourceName: data?.source || "Mobile" } }) + const type = await db.iam_principal_type.findOne({ where: { principalTypeName: data?.type || "Investor" } }) + return await db.iam_principal.create({ principalSource_xid: source.id, principalType_xid: type.id, ...data }) + }, + update: async (data) => await db.iam_principal.update(data, { where: { id: data.id } }), + updateBiometric: async (data) => { + const user = await db.iam_principal.findByPk(data.id) + if (!user) throw new ApiError(400, "User Not found") + return await db.transaction.execute(async (transactionOption) => { + await db.iam_principal.update(data, { where: { id: data.id }, ...transactionOption }) + await db.iam_principal_biometric.findCreateFind({ + where: { deviceId: data.deviceId, principal_xid: data.id }, + defaults: { deviceId: data.deviceId, biometric_type: data.biometric_type, principal_xid: data.id }, + ...transactionOption + }) + }) + }, + registerWithEmail: async (data) => { + return await db.transaction.execute(async (transactionOptions) => { + await db.iam_principal.update(data, { where: { id: data.id }, ...transactionOptions }) + return await db.investor_details.create({ principal_xid: data.id, country_xid: data.country_xid }, transactionOptions) + }) + }, + getById_lite: async (id) => await db.iam_principal.findByPk(id), + getByID: async (id) => await db.iam_principal.findByPk(id), + getByIdWithBiometric: async (id, deviceId) => await db.iam_principal.findByPk(id, { include: [{ association: "biometrics", where: { deviceId } }] }), + getByNumberWithISDCode: async (mobileNumber, ISDcode) => await db.iam_principal.findOne({ where: { mobileNumber, ISDcode }, include: [{ association: "investor_details" }] }), + togglesStatus: async (id) => { + const user = await db.iam_principal.findByPk(id) + if (!user) throw new ApiError(404, "not Found") + user.IsAppNotificationEnabled = !user.IsAppNotificationEnabled + user.save() + return user + }, + togglesNotificationStatus: async (principal_xid, deviceId, playerId, IsAppNotificationEnabled) => + await db.transaction.execute(async (transactionOptions) => { + await db.iam_principal.update({ IsAppNotificationEnabled: IsAppNotificationEnabled }, { where: { id: principal_xid }, ...transactionOptions }) + const [instane, boolean] = await db.iam_principal_notification.findOrCreate({ + where: { playerId, deviceId, principal_xid }, defaults: { + principal_xid, deviceId, playerId, IsAppNotificationEnabled, + }, ...transactionOptions + }) + if (!boolean) await db.iam_principal_notification.update({ IsAppNotificationEnabled }, { where: { id: instane.id }, ...transactionOptions }) + }), + ResetPassword: async (hashedPassword, id) => db.iam_principal.update({ password_hash: hashedPassword }, { where: { id } }), + getByEmail: async (email) => { + return await db.iam_principal.findOne({ + where: { emailAddress: email }, + include: [{ association: "principal_type", where: { id: iamConstant.principalTypeXid.OPTIFII_ADMIN }, through: { attributes: [] } }] + }); + } + +} \ No newline at end of file diff --git a/src/services/IAM/iam_principal_notification.service.js b/src/services/IAM/iam_principal_notification.service.js new file mode 100644 index 0000000..bfd414a --- /dev/null +++ b/src/services/IAM/iam_principal_notification.service.js @@ -0,0 +1,32 @@ +const { Op } = require("sequelize") +const db = require("../../models") + +module.exports = { + getPrincipalPlayerId: async (principal_xid) => { + const results = await db.iam_principal_notification.findAll({ + where: { principal_xid, IsAppNotificationEnabled: true }, + attributes: ['playerId'] + }); + + // Map the results to extract playerId directly into an array + return results.map(result => result.playerId); + }, + + getAllPlayerId: async () => { + return await db.iam_principal_notification.findAll({ + where: { IsAppNotificationEnabled: true }, + attributes: ['playerId'] + },) + }, + + getSpecificPlayerIds: async (principal_xids) => { + return await db.iam_principal_notification.findAll({ + where: { + principal_xid: { [Op.in]: principal_xids }, // No need to wrap `principal_xids` in an array + IsAppNotificationEnabled: true + }, + attributes: ['playerId'] + }) + // .then(result => result.map(record => record.playerId)); // Extracting playerId from each result + } +} \ No newline at end of file diff --git a/src/services/access/tokenService.js b/src/services/access/tokenService.js new file mode 100644 index 0000000..7f05d6e --- /dev/null +++ b/src/services/access/tokenService.js @@ -0,0 +1,8 @@ +const db = require("../../models"); + +module.exports={ + get: async (refreshToken) => { + return await db.token.findOne({ + where: { token: refreshToken, isblacklisted: false } }); + } +} \ No newline at end of file diff --git a/src/services/bcrypt/bcrypt.service.js b/src/services/bcrypt/bcrypt.service.js new file mode 100644 index 0000000..9b863e0 --- /dev/null +++ b/src/services/bcrypt/bcrypt.service.js @@ -0,0 +1,13 @@ +const bcrypt = require("bcrypt"); + +const { hashSync, compareSync, genSaltSync } = bcrypt; + +module.exports = { + hash: (data) => { + return hashSync(data, genSaltSync(10)); + }, + + compare: (data, hash) => { + return compareSync(data, hash); + }, +}; diff --git a/src/services/code/code.service.js b/src/services/code/code.service.js new file mode 100644 index 0000000..f870200 --- /dev/null +++ b/src/services/code/code.service.js @@ -0,0 +1,45 @@ +const crypto = require('crypto'); +const config = require('../../config/config'); +const ApiError = require('../../utils/handler/ApiError.handler'); +const algorithm = 'aes-256-cbc'; +const secretKey = crypto.createHash('sha256').update(config.code.secret).digest(); + +// Initialize blacklist if it's not already a Set +const blacklist = config.code.blacklist || new Set(); + +module.exports = { + encryptUserId: (userId) => { + try { + const userIdString = String(userId); // Ensure userId is a string + const iv = crypto.randomBytes(16); // New IV for each encryption + const cipher = crypto.createCipheriv(algorithm, secretKey, iv); + let encrypted = cipher.update(userIdString, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + return `${encrypted}-${iv.toString('hex')}`; + } catch (error) { + throw new ApiError(400, `Encryption failed: ${error.message}`); + } + }, + decryptUserId: (encryptedString) => { + try { + if (blacklist.has(encryptedString)) { + throw new ApiError(400, 'The code is blacklisted'); + } + + const [encryptedData, iv] = encryptedString.split('-'); + if (!encryptedData || !iv) { + throw new ApiError(400, 'Invalid code'); + } + + const decipher = crypto.createDecipheriv(algorithm, secretKey, Buffer.from(iv, 'hex')); + let decrypted = decipher.update(encryptedData, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + return decrypted; + } catch (error) { + throw new ApiError(400, "Invalid Code", [`Decryption failed: ${error.message}`]); + } + }, + addToBlacklist: (encryptedString) => { + blacklist.add(encryptedString); + } +}; diff --git a/src/services/corporate/corporate.service.js b/src/services/corporate/corporate.service.js new file mode 100644 index 0000000..66fea18 --- /dev/null +++ b/src/services/corporate/corporate.service.js @@ -0,0 +1,52 @@ +const { Op } = require("sequelize"); +const db = require("../../models"); +const corporateConstant = require("../../utils/constant/corporate.constant"); +const iamConstant = require("../../utils/constant/iam.constant"); + +module.exports = { + getCorporateExist: async (mobileNumber, ISDcode, emailAddress) => await db.corporate.findOne({ where: { mobileNumber, ISDcode, emailAddress } }), + create: async (data) => await db.corporate.create(data), + createWithOtherDetails: async (data) => await db.corporate.create(data, { include: [{ association: 'other_details' }] }), + update: async (data) => await db.corporate.update(data, { where: { id: data.id } }), + updateWithPricipalAndOtherDeatils: async (data) => await db.transaction.execute(async (transactionObject) => { + const principal = await db.iam_principal.create(data.principal, transactionObject) + await db.iam_principal_type_link.create({ principal_xid: principal.id, principalType_xid: data.principal.principalType_xid }) + await db.corporate.update(data, { where: { id: data.id }, ...transactionObject }) + await db.corporate_other_detail.create(data.other_detail, transactionObject); + await db.corporate_director.bulkCreate(data.directors, transactionObject) + return principal + }), + getCorporateListing: async (query) => { + return await db.pagination({ + model: db.corporate, + ...query, + where: { is_active: true }, + attributes: ['id', 'entity_name', 'corporate_name', 'emailAddress', 'corporate_code', 'onboarding_date', 'opted_for_expence', 'opted_for_benefit', 'opted_for_gifting'], + associations: [ + { association: "industry", attributes: ['id', 'industry_name'], required: false }, + { association: "corporate_type", attributes: ['id', 'corporate_type'], required: false }, + { association: "corporate_status", attributes: ['id', 'status'], required: false } + ], + order: [["updatedAt", "ASC"]], + searchableFields: Object.keys(db.corporate.getAttributes()), + }) + }, + + getById: async (id) => await db.corporate.findByPk(id, { + include: [ + { association: 'other_details', required: false }, + { association: 'director', required: false }, + { association: "principal", required: false, attributes: ["userName", "firstName", "lastName", "emailAddress", "ISDcode", "mobileNumber"] } + ] + }), + getByID_lite: async (id) => await db.corporate.findByPk(id), + checkIsSubmited: async (id) => await db.corporate.findOne({ + where: { id, corporate_status_xid: { [Op.eq]: corporateConstant.statusXid.SUBMITTED } }, + include: [{ + association: "principal", + attributes: ["fullName"], + required: false, + include: [{ association: "principal_type", where: { id: iamConstant.principalTypeXid.CORPORATE_ADMIN }, through: { attributes: [] } }] + }] + }) +} diff --git a/src/services/crypto/crypto.service.js b/src/services/crypto/crypto.service.js new file mode 100644 index 0000000..6996abf --- /dev/null +++ b/src/services/crypto/crypto.service.js @@ -0,0 +1,62 @@ +const crypto = require("crypto"); +const path = require("path"); +const fs = require('fs'); + +const publicKeyPem = fs.readFileSync(path.join(__dirname, '../../keys/public_key.pem'), 'utf8'); +const privateKeyPem = fs.readFileSync(path.join(__dirname, '../../keys/rsa_private_key.pem'), 'utf8'); + +module.exports = { + encryptWithPublicKey: async (jsonData) => { + const buffer = Buffer.from(JSON.stringify(jsonData)); + const encrypted = crypto.publicEncrypt({ + key: publicKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING + }, buffer); + return encrypted.toString("base64"); + }, + + decryptWithPrivateKey: async (encryptedData) => { + try { + const buffer = Buffer.from(encryptedData, 'base64'); + const decrypted = crypto.privateDecrypt({ + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING + }, buffer); + const value = decrypted.toString('utf8'); + console.log(value) + return JSON.parse(value); + } catch (error) { + console.error('Decryption Error:', error); + throw error; + } + }, + + decryptKey: async (encryptedKey) => { + const decodedKey = Buffer.from(encryptedKey, 'base64'); + const decryptedKey = crypto.privateDecrypt( + { + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING, + }, + decodedKey + ); + return decryptedKey; + }, + + getIV: async (decodedData) => { + return decodedData.slice(0, 16); + }, + + base64Decode: async (data) => { + return Buffer.from(data, 'base64'); + }, + + decryptData: async (decodedData, sessionKey, iv) => { + const decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv); + decipher.setAutoPadding(true); + let decrypted = decipher.update(decodedData.slice(16)); + decrypted = Buffer.concat([decrypted, decipher.final()]); + const value = decrypted.toString('utf8'); + return JSON.parse(value); + } +}; diff --git a/src/services/emailTemplate/otpSenderTemplate.js b/src/services/emailTemplate/otpSenderTemplate.js new file mode 100644 index 0000000..aec52a1 --- /dev/null +++ b/src/services/emailTemplate/otpSenderTemplate.js @@ -0,0 +1,31 @@ +const { transporter } = require("../../config/nodemailerConfig"); +const config = require("../../config/config"); +const logger = require("../../config/logger"); + +module.exports = { + loginOtp: async (to, otp) => { + try { + if (config.byPassEmail){ + logger.info(`Email to ${to} has been bypassed due to bypassEmail configuration.`); + return true; + } + const emailOptions = { + from: config.email.from, + to: to, + subject: "Login OTP", + text: "Login OTP", + html: ` +
+

Hi, your OTP for login is -> ${otp},
+ Please do not share this otp with anyone.

+
+`, + }; + const result = await transporter.sendMail(emailOptions); + return result; + } catch (error) { + logger.error("Error sending email:", error); + throw new Error("MPIN reset email not sent: " + error.message); + } + }, +} \ No newline at end of file diff --git a/src/services/emailTemplate/resetOtpTemplate.js b/src/services/emailTemplate/resetOtpTemplate.js new file mode 100644 index 0000000..fea37c4 --- /dev/null +++ b/src/services/emailTemplate/resetOtpTemplate.js @@ -0,0 +1,65 @@ +const { transporter } = require("../../config/nodemailerConfig"); +const config = require("../../config/config"); +const logger = require("../../config/logger"); + +module.exports = { + resetOtp: async (to, otp) => { + try { + const emailOptions = { + from: config.email.from, + to: to, + subject: "Reset Your OTP", + text: `We received a request to reset your MPIN. Your One-Time Password (OTP) is: ${otp}. Please use this OTP to reset your MPIN. If you did not request this change, please contact us immediately at info@tanamicapital.com or +973 3633 1331.`, + html: ` + + +
+
+
+ + Tanami Logo + +
+
+

Reset Your MPIN.

+

We received a request to reset your MPIN.

+

Your One-Time Password (OTP) is: ${otp}.

+

+ Please use this OTP to reset your MPIN. If you did not request this change, please contact us immediately
at + info@tanamicapital.com or +973 3633 1331 +

+
+

Thank You!
Tanami Team

+ +
+
+ + +`, + }; + const result = await transporter.sendMail(emailOptions); + return result; + } catch (error) { + logger.error("Error sending email:", error); + throw new Error("MPIN reset email not sent: " + error.message); + } + }, +} \ No newline at end of file diff --git a/src/services/iam_principal_otp/iamPrincipalOTP.service.js b/src/services/iam_principal_otp/iamPrincipalOTP.service.js new file mode 100644 index 0000000..99fc1c1 --- /dev/null +++ b/src/services/iam_principal_otp/iamPrincipalOTP.service.js @@ -0,0 +1,20 @@ +const { Op } = require("sequelize"); +const db = require("../../models"); +const ApiError = require("../../utils/handler/ApiError.handler"); + +module.exports = { + create: async (data) => { + await db.iam_principal_otp.destroy({ + where: { principal_xid: data.principal_xid, isUsed: { [Op.eq]: false } }, force: true + }); + return await db.iam_principal_otp.create(data); + }, + getOtp: async (principal_xid) => { + const data = await db.iam_principal_otp.findOne({ where: { principal_xid, isUsed: false }, }); + if (!data) { throw new ApiError(400, "Invalid OTP") } + const validTillTimestamp = new Date(data.validTill).getTime(); + const currentTime = Date.now(); + if (currentTime > validTillTimestamp) { throw new ApiError(400, "OTP has expired") } + return data + } +} \ No newline at end of file diff --git a/src/services/index.js b/src/services/index.js new file mode 100644 index 0000000..50f4358 --- /dev/null +++ b/src/services/index.js @@ -0,0 +1,13 @@ +module.exports = { + tokenService: require('./token/token.service'), + iamPrincipalService: require('./IAM/iam_principal.service'), + otpSenderTemplate: require('./emailTemplate/otpSenderTemplate'), + bcryptService: require('./bcrypt/bcrypt.service'), + codeService: require('./code/code.service'), + iamPrincipalOTPService: require('./iam_principal_otp/iamPrincipalOTP.service'), + resetOtpTemplate: require('./emailTemplate/resetOtpTemplate'), + tokenNewService: require('./access/tokenService'), + corporateService: require('./corporate/corporate.service'), + industryService: require('./industry/industry.service'), + cryptoService: require('./crypto/crypto.service'), +} \ No newline at end of file diff --git a/src/services/industry/industry.service.js b/src/services/industry/industry.service.js new file mode 100644 index 0000000..3531fc3 --- /dev/null +++ b/src/services/industry/industry.service.js @@ -0,0 +1,5 @@ +const db = require("../../models"); + +module.exports = { + getAll: async () => await db.industry.findAll(), +}; diff --git a/src/services/token/token.service.js b/src/services/token/token.service.js new file mode 100644 index 0000000..b6ac352 --- /dev/null +++ b/src/services/token/token.service.js @@ -0,0 +1,50 @@ +const jwt = require('jsonwebtoken') +const config = require("../../config/config"); +const moment = require('moment'); +const db = require('../../models'); +const { tokenTypes } = require('../../config/tokens'); +const generateToken = (userId, countryId, languageId, expires, type, secret = config.jwt.secret) => { + const payload = { userId, countryId, languageId, iat: moment().unix(), exp: moment(expires).unix(), type, }; + return jwt.sign(payload, secret) +} + +const saveToken = async (token, userId, expires, type, isblacklisted = false) => { + return await db.token.create({ token, userId, expires: moment(expires).toDate(), type, isblacklisted }) +} +module.exports = { + verifyToken: (token, type) => { + return jwt.verify(token, config.jwt.secret) + }, + generateAuthTokens: async (user) => { + const { id, investor_details } = user + const accessTokenExpires = moment().add(config.jwt.accessExpirationMinutes, 'minutes'); + const accessToken = generateToken(id, investor_details?.country_xid, investor_details?.defaultLanguage_xid, accessTokenExpires, tokenTypes.ACCESS); + + const refreshTokenExpires = moment().add(config.jwt.refreshExpirationDays, 'days'); + const refreshToken = generateToken(id, investor_details?.country_xid, investor_details?.defaultLanguage_xid, null, refreshTokenExpires, tokenTypes.REFRESH); + await saveToken(refreshToken, id, refreshTokenExpires, tokenTypes.REFRESH); + + return { + access: { + token: accessToken, + expires: moment(accessTokenExpires).toDate(), + }, + refresh: { + token: refreshToken, + expires: moment(refreshTokenExpires).toDate(), + }, + }; + }, + reGenerateAccessTokens: async (user) => { + const { id, investor_details } = user + const accessTokenExpires = moment().add(config.jwt.accessExpirationMinutes, 'minutes'); + const accessToken = generateToken(id, investor_details?.country_xid, investor_details?.defaultLanguage_xid, accessTokenExpires, tokenTypes.ACCESS); + return { + access: { + token: accessToken, + expires: moment(accessTokenExpires).toDate(), + } + }; + }, + generateToken, +} \ No newline at end of file diff --git a/src/utils/constant/corporate.constant.js b/src/utils/constant/corporate.constant.js new file mode 100644 index 0000000..9626c8b --- /dev/null +++ b/src/utils/constant/corporate.constant.js @@ -0,0 +1,26 @@ +module.exports = { + corporateType: { + PRIVATE: "Private", + PUBLIC: "Public", + LLP: "LLP" + }, + industryType: { + TECHNOLOGY: "Technology", + HEALTHCARE: "Healthcare", + FINANCE: "Finance", + SERVICES: "Services" + }, + corporateStatus: { + REQUESTED: "Requested", + APPROVED: "Approved", + REJECTED: "Rejected", + SUBMITTED: "Submitted" + }, + statusXid: { + REQUESTED: 1, + SUBMITTED: 2, + REGISTERD: 3, + APPROVED: 4, + REJECTED: 5, + } +} \ No newline at end of file diff --git a/src/utils/constant/iam.constant.js b/src/utils/constant/iam.constant.js new file mode 100644 index 0000000..5c03ceb --- /dev/null +++ b/src/utils/constant/iam.constant.js @@ -0,0 +1,14 @@ +module.exports = { + + otpPurpose : { + PASSWORD_RESET : "Password reset", + RESEND: "Resend", + LOGIN: "Login" + }, + + principalTypeXid: { + OPTIFII_ADMIN: 1, + CORPORATE_ADMIN: 2, + USER: 3 + } +} \ No newline at end of file diff --git a/src/utils/handler/ApiError.handler.js b/src/utils/handler/ApiError.handler.js new file mode 100644 index 0000000..4358540 --- /dev/null +++ b/src/utils/handler/ApiError.handler.js @@ -0,0 +1,41 @@ +/** + * Custom error class for handling API errors. Extends the native Error class. + * @class ApiError + * @extends Error + * + * @param {number} statusCode - HTTP status code associated with the error. + * @param {string} [message="Something went wrong"] - Error message (default is a generic message). + * @param {Array} [errors=[]] - Array containing specific error details or additional information. + * @param {boolean} [isOperational=true] - Indicates if the error is operational or not. + * @param {string} [stack=""] - Stack trace for the error (optional, defaults to an empty string). + */ +class ApiError extends Error { + constructor( + statusCode, + message = "Something went wrong", + errors = [], + isOperational = true, + stack = "" + ) { + // Call the constructor of the parent class (Error) + super(message); + + // Custom properties for API error handling + this.statusCode = statusCode; // HTTP status code associated with the error. + this.data = null; // Additional data associated with the error (initially set to null). + this.message = message; // Error message for the API response. + this.success = false; // Indicates the failure nature of the API request. + this.errors = errors; // Specific error details or additional information. + this.isOperational = isOperational; // Indicates if the error is operational or not. + + // Set the stack trace if provided; otherwise, capture the current stack trace. + if (stack) { + this.stack = stack; // Provided stack trace. + } else { + Error.captureStackTrace(this, this.constructor); // Capture the current stack trace. + } + } +} + +// Export the ApiError class for use in other modules. +module.exports = ApiError; diff --git a/src/utils/handler/ApiResponse.handler.js b/src/utils/handler/ApiResponse.handler.js new file mode 100644 index 0000000..7781b33 --- /dev/null +++ b/src/utils/handler/ApiResponse.handler.js @@ -0,0 +1,19 @@ +/** + * Class representing a standard API response. + * @class ApiResponse + * + * @param {number} statusCode - HTTP status code associated with the response. + * @param {any} data - Data to be returned in the response. + * @param {string} [message="Success"] - Response message (default is "Success"). + */ +class ApiResponse { + constructor(statusCode, data, message = "Success") { + this.statusCode = statusCode; // HTTP status code associated with the response. + this.data = data; // Data to be returned in the response. + this.message = message; // Response message (default is "Success"). + this.success = statusCode < 400; // Indicates if the response is successful based on the status code. + } +} + +// Export the ApiResponse class for use in other modules. +module.exports = ApiResponse; diff --git a/src/utils/handler/Async.handler.js b/src/utils/handler/Async.handler.js new file mode 100644 index 0000000..0ad3a34 --- /dev/null +++ b/src/utils/handler/Async.handler.js @@ -0,0 +1,11 @@ +/** + * Asynchronous error handler for Express routes. + * @function AsyncHandler + * + * @param {Function} fn - Asynchronous function to be executed. + * @returns {Function} Middleware function that handles errors for asynchronous routes. + */ +module.exports.AsyncHandler = (fn) => (req, res, next) => { + // Wrap the asynchronous function in a promise and handle any errors by passing them to the next middleware. + Promise.resolve(fn(req, res, next)).catch(next); +}; diff --git a/src/utils/handler/pick.handler.js b/src/utils/handler/pick.handler.js new file mode 100644 index 0000000..0d3ba4b --- /dev/null +++ b/src/utils/handler/pick.handler.js @@ -0,0 +1,21 @@ +/** + * Create an object composed of the picked object properties. + * @function pick + * + * @param {Object} object - The source object to pick properties from. + * @param {string[]} keys - The array of property names to pick from the source object. + * @returns {Object} New object with only the picked properties. + */ +const pick = (object, keys) => { + return keys.reduce((obj, key) => { + // Check if the object has the specified property + if (object && Object.prototype.hasOwnProperty.call(object, key)) { + obj[key] = object[key]; // Assign the property to the new object + } + return obj; // Return the new object + }, {}); // Initialize the new object as an empty object + }; + + // Export the pick function for use in other modules. + module.exports = pick; + \ No newline at end of file diff --git a/src/utils/helper/aesCrypto.helper.js b/src/utils/helper/aesCrypto.helper.js new file mode 100644 index 0000000..d85184d --- /dev/null +++ b/src/utils/helper/aesCrypto.helper.js @@ -0,0 +1,21 @@ +const crypto = require('crypto'); + +// AES encryption function using crypto +function aesEncrypt(trandata, key) { + const iv = Buffer.from("PGKEYENCDECIVSPC"); // 16-byte IV for AES + const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv); + let encrypted = cipher.update(trandata, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + return encrypted; +} + +// AES decryption function using crypto +function aesDecryption(encryptedHex, key) { + const iv = Buffer.from("PGKEYENCDECIVSPC"); + const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv); + let decrypted = decipher.update(encryptedHex, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + return decrypted; +} + +module.exports = { aesEncrypt, aesDecryption }; diff --git a/src/utils/helper/emailValidator.helper.js b/src/utils/helper/emailValidator.helper.js new file mode 100644 index 0000000..794db4e --- /dev/null +++ b/src/utils/helper/emailValidator.helper.js @@ -0,0 +1,30 @@ +const dns = require("node:dns"); +// Async function to resolve MX records for a domain +async function resolveMx(domain, recordType) { + return new Promise((resolve, reject) => { + dns.resolveMx(domain, (err, mxRecords) => { + if (err) { + reject(err); + return; + } + const addresses = mxRecords.map((mxRecord) => mxRecord.exchange); + resolve(addresses); + }); + }); +} +// Async function to check email address validity +async function checkEmailValidity(email) { + try { + const domain = email?.split("@")[1]; + const addresses = await resolveMx(domain, "MX"); + + if (addresses && addresses?.length > 0) { + return true; + } + return false; // No MX record exists + } catch (err) { + return false; // Error occurred + } +} + +module.exports = checkEmailValidity \ No newline at end of file diff --git a/src/utils/helper/fileValidator.helper.js b/src/utils/helper/fileValidator.helper.js new file mode 100644 index 0000000..6477a40 --- /dev/null +++ b/src/utils/helper/fileValidator.helper.js @@ -0,0 +1,12 @@ +function isValidFileSize(value) { + // Check the file size here, e.g., to ensure it's not larger than a specific limit. + // Adjust the maximum size as needed (in bytes). + const maxSizeInBytes = 10 * 1024 * 1024; // 10 MB + + if (value && value.size <= maxSizeInBytes) { + return true; // Valid file size + } + + return false; // Invalid file size +} +module.exports = isValidFileSize \ No newline at end of file diff --git a/src/utils/helper/genrateCodeName.helper.js b/src/utils/helper/genrateCodeName.helper.js new file mode 100644 index 0000000..638ee6d --- /dev/null +++ b/src/utils/helper/genrateCodeName.helper.js @@ -0,0 +1,36 @@ +function generateCompanyCode(input, count) { + let abbreviation; + + // Split the input by spaces to check if it's a single word or multiple words + const words = input.split(' '); + + // If it's a single word and more than 5 characters + if (words.length === 1 && input.length > 5) { + // Use the first 4 letters of the single word + abbreviation = input.slice(0, 4).toUpperCase(); // "Accenture" -> "ACCE" + } else if (words.length > 1) { + // Multiple words: take the first letter of each word + abbreviation = words.map(word => word[0].toUpperCase()).join(''); // "J. P. Morgan" -> "JPM" + } else { + // For other cases (like short single words), use the input as uppercase + abbreviation = input.toUpperCase(); + } + + // Get the current year + const currentYear = new Date().getFullYear(); + + // Increment the count: If the passed count is 0, set it to 1; otherwise, add 1 to the count + const incrementedCount = (count === 0) ? 1 : count + 1; + + // Format the incremented count as '0001' with leading zeros + const countString = String(incrementedCount).padStart(4, '0'); // Assuming count is up to 9999 + + + // Combine abbreviation, year, and count to form the code + const code = `${abbreviation}${currentYear}${countString}`; + + return code; +} + + +module.exports = generateCompanyCode \ No newline at end of file diff --git a/src/utils/helper/notificationMsg.helper.js b/src/utils/helper/notificationMsg.helper.js new file mode 100644 index 0000000..c9fe930 --- /dev/null +++ b/src/utils/helper/notificationMsg.helper.js @@ -0,0 +1,131 @@ +const { sendNotification } = require("../../services/push_notification/onesignal.service"); + +// Function to get deposit received message +const getDepositReceivedMessage = amount => ({ + en: `Funds Added to Your Wallet: A deposit of $${amount} has been credited to your account.`, + ar: `تمت إضافة أموال إلى محفظتك: تمت إضافة إيداع بقيمة ${amount} دولار إلى حسابك.` +}); + +// Function to get educational material published message +const getEducationalMaterialPublishedMessage = () => ({ + en: 'Learn and Grow! Expand your knowledge with new educational material in our Academy.', + ar: 'تعلم ونم! وسع معرفتك من خلال المواد التعليمية الجديدة في أكاديميتنا.' +}); + +// Function to get investment opportunity cancelled message +const investmentOpportunityCancelled = investmentName => ({ + en: `Investment Opportunity Cancelled: ${investmentName} has been cancelled.`, + ar: `تم إلغاء فرصة الاستثمار: ${investmentName} قد تم إلغاؤه.` +}); + +// Function to get investor qualification upgrade message +const investorQualificationUpgrade = () => ({ + en: 'Congratulations, Investor! Your Investor Qualification has been upgraded. Enjoy enhanced benefits!', + ar: 'تهانينا، مستثمر! تم ترقية مؤهلاتك كمستثمر. استمتع بالمزايا المعززة!' +}); + +// Function to get KYC status approved message +const kycStatusApproved = () => ({ + en: 'KYC Approved: Great news! Your KYC verification is successful.', + ar: 'تمت الموافقة على KYC: أخبار رائعة! تم التحقق من KYC بنجاح.' +}); + +// Function to get KYC status declined message +const kycStatusDeclined = () => ({ + en: 'KYC Update: Your KYC status requires attention. Please pass the verification again.', + ar: 'تحديث KYC: حالة KYC الخاصة بك تتطلب انتباهاً. يرجى إعادة إجراء التحقق.' +}); + +// Function to get new investment opportunity message +const newInvestmentOpportunity = () => ({ + en: 'Discover New Opportunities! A fresh investment opportunity awaits you. Dive in now!', + ar: 'اكتشف الفرص الجديدة! تنتظرك فرصة استثمارية جديدة. ابدأ الآن!' +}); + +// Function to get subscription investment closed message +const subscriptionInvestmentClosed = () => ({ + en: 'Investment Update: Your investment opportunity has just closed.', + ar: 'تحديث الاستثمار: لقد تم إغلاق فرصة استثمارك للتو.' +}); + +// Function to get subscription investment updated message +const subscriptionInvestmentUpdated = () => ({ + en: 'Investment Status Alert: Your investment subscription details have been updated.', + ar: 'تنبيه حالة الاستثمار: تمت تحديث تفاصيل اشتراكك في الاستثمار.' +}); + +// Function to get withdrawal completed message +const withdrawalCompleted = () => ({ + en: 'Withdrawal Complete: Your withdrawal is processed. Check your bank for funds!', + ar: 'اكتمل السحب: تمت معالجة سحبك. تحقق من بنكك للحصول على الأموال!' +}); + +// Function to send new investment opportunity notification +const sendNewInvestmentOpportunityNotification = async (investmentName, manualDate, manualTime, expectedReturn, playerIds = [], imageUrl = '', additionalData = {}) => { + const title = 'New investment opportunity'; + const message = `${investmentName} launching on ${manualDate} at ${manualTime} with an expected return of ${expectedReturn}%. Tap for more details.`; + return await sendNotification(title, message, playerIds, imageUrl, additionalData); +}; + +// Function to send investment open notification +const sendInvestmentOpenNotification = async (investmentName, playerIds = [], imageUrl = '', additionalData = {}) => { + const title = `${investmentName} is LIVE`; + const message = `${investmentName} is now open for investment! Tap for more details.`; + return await sendNotification(title, message, playerIds, imageUrl, additionalData); +}; + +// Function to send investment fully subscribed notification +const sendInvestmentFullySubscribedNotification = async (investmentName, playerIds = [], imageUrl = '', additionalData = {}) => { + const title = `${investmentName} fully subscribed`; + const message = `${investmentName} has been fully subscribed and is now closed to new investors.`; + return await sendNotification(title, message, playerIds, imageUrl, additionalData); +}; + +// Function to send deposit received notification +const sendDepositReceivedNotification = async (playerIds = [], imageUrl = '', additionalData = {}) => { + const title = 'Deposit received'; + const message = 'A new deposit has been made into your Tanami wallet. Explore exclusive investment opportunities only at Tanami.'; + return await sendNotification(title, message, playerIds, imageUrl, additionalData); +}; + +// Function to send distribution notice notification +const sendDistributionNoticeNotification = async (investmentName, playerIds = [], imageUrl = '', additionalData = {}) => { + const title = 'Distribution notice'; + const message = `New distribution received regarding your investment in ${investmentName}. Tap for more details.`; + return await sendNotification(title, message, playerIds, imageUrl, additionalData); +}; + +// Function to send KYC approved notification +const sendKYCApprovedNotification = async (playerIds = [], imageUrl = '', additionalData = {}) => { + const title = 'You\'re verified!'; + const message = 'KYC approved - You\'re all set to start investing! Tap to explore the latest exclusive opportunities available.'; + return await sendNotification(title, message, playerIds, imageUrl, additionalData); +}; + +// Function to send investor status upgrade notification +const sendInvestorStatusUpgradeNotification = async (playerIds = [], imageUrl = '', additionalData = {}) => { + const title = 'You\'ve been upgraded!'; + const message = 'Congrats! You can now enjoy investing with no limits! Tap to explore the latest exclusive opportunities available.'; + return await sendNotification(title, message, playerIds, imageUrl, additionalData); +}; + +// Exporting functions +module.exports = { + getDepositReceivedMessage, + getEducationalMaterialPublishedMessage, + investmentOpportunityCancelled, + investorQualificationUpgrade, + kycStatusApproved, + kycStatusDeclined, + newInvestmentOpportunity, + subscriptionInvestmentClosed, + subscriptionInvestmentUpdated, + withdrawalCompleted, + sendNewInvestmentOpportunityNotification, + sendInvestmentOpenNotification, + sendInvestmentFullySubscribedNotification, + sendDepositReceivedNotification, + sendDistributionNoticeNotification, + sendKYCApprovedNotification, + sendInvestorStatusUpgradeNotification +}; diff --git a/src/utils/helper/otpGenrator.helper.js b/src/utils/helper/otpGenrator.helper.js new file mode 100644 index 0000000..0b512ba --- /dev/null +++ b/src/utils/helper/otpGenrator.helper.js @@ -0,0 +1,16 @@ +const config = require("../../config/config"); + +const generateOTP = () => { + var digits = "0123456789"; + let OTP = ""; + if (config.byPassOTP) { + OTP = "123456" + } else { + for (let i = 0; i < 6; i++) { + OTP += digits[Math.floor(Math.random() * 10)]; + } + } + return OTP; +} +module.exports = generateOTP + diff --git a/src/utils/helper/transactionNumberGenrator.helper.js b/src/utils/helper/transactionNumberGenrator.helper.js new file mode 100644 index 0000000..32d9ae2 --- /dev/null +++ b/src/utils/helper/transactionNumberGenrator.helper.js @@ -0,0 +1,42 @@ +const moment = require('moment'); + +class TransactionNumberGenerator { + constructor() { + this.timestampMap = new Map(); + this.lock = { isLocked: false }; + } + + _acquireLock() { + while (this.lock.isLocked) { } + this.lock.isLocked = true; + } + + _releaseLock() { + this.lock.isLocked = false; + } + + // Convert date and time to Unix timestamp + _getUnixTimestamp(dateTime) { + return moment(dateTime, 'YYYY-MM-DD HH:mm:ss').unix(); + } + + generateUniqueTimestamp(dateTime) { + this._acquireLock(); + + const timestamp = this._getUnixTimestamp(dateTime); + if (!this.timestampMap.has(timestamp)) { + this.timestampMap.set(timestamp, 0); + } + let counter = this.timestampMap.get(timestamp) + 1; + this.timestampMap.set(timestamp, counter); + + this._releaseLock(); + + // Create unique number with timestamp and counter + const uniqueNumber = ((timestamp % 10000000000) * 1000 + counter).toString().padStart(11, '0'); + + return uniqueNumber; + } +} + +module.exports = TransactionNumberGenerator \ No newline at end of file diff --git a/src/validation/auth/admin.schema.js b/src/validation/auth/admin.schema.js new file mode 100644 index 0000000..8f7c3ce --- /dev/null +++ b/src/validation/auth/admin.schema.js @@ -0,0 +1,15 @@ +const yup = require('yup'); + +module.exports={ + body: yup.object().shape({ + emailAddress: yup + .string() + .email('Invalid email format') // Ensure the email address is in a valid format + .required('Email address is required'), // Validation message for required field + + password_hash: yup + .string() + .required('Password hash is required') // Validation message for required field + }) + +} diff --git a/src/validation/auth/biometric.schema.js b/src/validation/auth/biometric.schema.js new file mode 100644 index 0000000..ed6299b --- /dev/null +++ b/src/validation/auth/biometric.schema.js @@ -0,0 +1,17 @@ +const yup = require('yup'); + +module.exports = { + body: yup.object().shape({ + is_2FA_on: yup + .boolean() + .required('2FA status is required'), + deviceId: yup + .string() + // .matches(/^QKQ1\.\d{6}\.\d{3}$/, 'Invalid device ID format') + .required('Device ID is required'), + biometric_type: yup + .string() + .oneOf(['fingerprint', 'face'], 'Biometric type must be one of: fingerprint, face') + .notRequired(), + }), +}; diff --git a/src/validation/auth/forgetPassword.schema.js b/src/validation/auth/forgetPassword.schema.js new file mode 100644 index 0000000..e087cda --- /dev/null +++ b/src/validation/auth/forgetPassword.schema.js @@ -0,0 +1,10 @@ +const yup = require("yup"); + +module.exports = { + body: yup.object().shape({ + emailAddress: yup + .string() + .email("Invalid email format") // Ensure the email address is in a valid format + .required("Email address is required"), // Validation message for required field + }), +}; diff --git a/src/validation/auth/index.js b/src/validation/auth/index.js new file mode 100644 index 0000000..9a38548 --- /dev/null +++ b/src/validation/auth/index.js @@ -0,0 +1,10 @@ +module.exports = { + otpVerification: require('./otpVerification.schema'), + registration: require('./registration.schema'), + login: require('./login.schema'), + biometric: require('./biometric.schema'), + updatePassword: require('./updatePassword.schema'), + resetPassword: require('./resetPaasword.schema'), + adminLogin: require('./admin.schema'), + forgetPassword: require('./forgetPassword.schema') +} \ No newline at end of file diff --git a/src/validation/auth/login.schema.js b/src/validation/auth/login.schema.js new file mode 100644 index 0000000..377add8 --- /dev/null +++ b/src/validation/auth/login.schema.js @@ -0,0 +1,16 @@ +const yup = require('yup'); +module.exports = { + body: yup.object().shape({ + mobileNumber: yup + .string() + .required('Mobile number is required') + .matches(/^[0-9]+$/, 'Mobile number must be digits only') + .min(8, 'Mobile number must be at least 8 digits') + .max(10, 'Mobile number must be at most 10 digits'), + ISDcode: yup + .string() + .required('ISD code is required') + .matches(/^\+\d{1,3}$/, 'ISD code must be in the format + followed by 1 to 3 digits'), + password: yup.string().required("Password is required") + }), +} \ No newline at end of file diff --git a/src/validation/auth/otpVerification.schema.js b/src/validation/auth/otpVerification.schema.js new file mode 100644 index 0000000..5579849 --- /dev/null +++ b/src/validation/auth/otpVerification.schema.js @@ -0,0 +1,10 @@ +const yup = require('yup'); +module.exports = { + body: yup.object().shape({ + otp: yup + .string() + .required('OTP is required') + .matches(/^[0-9]{6}$/, 'OTP must be exactly 6 digits'), + + }), +} \ No newline at end of file diff --git a/src/validation/auth/registration.schema.js b/src/validation/auth/registration.schema.js new file mode 100644 index 0000000..9731371 --- /dev/null +++ b/src/validation/auth/registration.schema.js @@ -0,0 +1,41 @@ +const yup = require('yup'); +const checkEmailValidity = require('../../utils/helper/emailValidator.helper'); +module.exports = { + body: yup.object().shape({ + firstName: yup + .string() + .required('First name is required') + .min(2, 'First name must be at least 2 characters long') + .max(35, 'First name must be at most 50 characters long'), + lastName: yup + .string() + .required('Last name is required') + .min(2, 'Last name must be at least 2 characters long') + .max(35, 'Last name must be at most 50 characters long'), + emailAddress: yup + .string() + .email("Invalid email address") + .required("Email address is required") + .min(6, "Email address must be at least 6 characters long") + .max(255, "Email address can be at most 255 characters long") + .test("emailValidity", "Email address is invalid", async function (value) { + if (!value) { + return true; // Allow if the field is empty + } + return await checkEmailValidity(value); + }), + password: yup + .string() + .required('Password is required') + .min(8, 'Password must be at least 8 characters long') + .max(16, 'Password must be at most 50 characters long') + .matches(/[A-Z]/, 'Password must contain at least one uppercase letter') + .matches(/[a-z]/, 'Password must contain at least one lowercase letter') + .matches(/[0-9]/, 'Password must contain at least one number') + .matches(/[@$!%*?&#]/, 'Password must contain at least one special character'), + confirmPassword: yup + .string() + .oneOf([yup.ref('password'), null], 'Passwords must match') + .required('Confirm password is required'), + }), +} \ No newline at end of file diff --git a/src/validation/auth/resetPaasword.schema.js b/src/validation/auth/resetPaasword.schema.js new file mode 100644 index 0000000..941f9ee --- /dev/null +++ b/src/validation/auth/resetPaasword.schema.js @@ -0,0 +1,27 @@ + +const yup = require('yup'); +module.exports = { + body: yup.object().shape({ + password: yup + .string() + .required('Password is required') + .min(8, 'Password must be at least 8 characters long') + .max(16, 'Password must be at most 50 characters long') + .matches(/[A-Z]/, 'Password must contain at least one uppercase letter') + .matches(/[a-z]/, 'Password must contain at least one lowercase letter') + .matches(/[0-9]/, 'Password must contain at least one number') + .matches(/[@$!%*?&#]/, 'Password must contain at least one special character'), + confirmPassword: yup + .string() + .oneOf([yup.ref('password'), null], 'Passwords must match') + .required('Confirm new password is required'), + code: yup + .string() + // .matches(/^[A-Za-z0-9-]{36,64}$/, 'Code must be between 36 and 64 alphanumeric characters or hyphens') + .required('Code is required'), + }) +} + + + + diff --git a/src/validation/auth/updatePassword.schema.js b/src/validation/auth/updatePassword.schema.js new file mode 100644 index 0000000..f7972b5 --- /dev/null +++ b/src/validation/auth/updatePassword.schema.js @@ -0,0 +1,22 @@ +const yup = require('yup'); +module.exports = { + body: yup.object().shape({ + oldPassword: yup + .string() + .required('Old password is required'), + newPassword: yup + .string() + .required('Password is required') + .min(8, 'Password must be at least 8 characters long') + .max(16, 'Password must be at most 50 characters long') + .matches(/[A-Z]/, 'Password must contain at least one uppercase letter') + .matches(/[a-z]/, 'Password must contain at least one lowercase letter') + .matches(/[0-9]/, 'Password must contain at least one number') + .matches(/[@$!%*?&#]/, 'Password must contain at least one special character'), + confirmNewPassword: yup + .string() + .oneOf([yup.ref('newPassword'), null], 'Passwords must match') + .required('Confirm new password is required') + + }), +} \ No newline at end of file diff --git a/src/validation/common/code.schema.js b/src/validation/common/code.schema.js new file mode 100644 index 0000000..d93b6ce --- /dev/null +++ b/src/validation/common/code.schema.js @@ -0,0 +1,9 @@ +const yup = require('yup'); +module.exports = { + body: yup.object().shape({ + code: yup + .string() + // .matches(/^[A-Za-z0-9-]{36,64}$/, 'Code must be between 36 and 64 alphanumeric characters or hyphens') + .required('Code is required'), + }), +} \ No newline at end of file diff --git a/src/validation/common/id.schema.js b/src/validation/common/id.schema.js new file mode 100644 index 0000000..4e98cce --- /dev/null +++ b/src/validation/common/id.schema.js @@ -0,0 +1,11 @@ +const yup = require('yup'); +module.exports = { + params: yup.object().shape({ + id: yup + .number() + .nullable() + .typeError("ID must be a number") + .positive("ID must be a positive number") + .required('ID is required') + }), +} \ No newline at end of file diff --git a/src/validation/common/index.js b/src/validation/common/index.js new file mode 100644 index 0000000..da25a22 --- /dev/null +++ b/src/validation/common/index.js @@ -0,0 +1,5 @@ +module.exports = { + search: require('./search.schema'), + id: require('./id.schema'), + code: require('./code.schema') +} \ No newline at end of file diff --git a/src/validation/common/search.schema.js b/src/validation/common/search.schema.js new file mode 100644 index 0000000..5e1ca9d --- /dev/null +++ b/src/validation/common/search.schema.js @@ -0,0 +1,8 @@ +const yup = require('yup'); +module.exports = { + query: yup.object().shape({ + page: yup.number().integer().min(1).optional().default(1), + size: yup.number().integer().min(1).optional().default(10), + search: yup.string().max(100).optional(), + }), +} \ No newline at end of file diff --git a/src/validation/corporate/corporateQuickAdd.schema.js b/src/validation/corporate/corporateQuickAdd.schema.js new file mode 100644 index 0000000..21289f4 --- /dev/null +++ b/src/validation/corporate/corporateQuickAdd.schema.js @@ -0,0 +1,38 @@ +const yup = require('yup'); +const { email } = require('../../config/config'); +const checkEmailValidity = require('../../utils/helper/emailValidator.helper'); + +module.exports = { + body: yup.object().shape({ + entity_name: yup + .string() + .required('Entity name is required') + .max(100, 'Entity name should not be greater than 100 characters'), + corporate_name: yup + .string() + .required('Company name is required.') + .max(100, 'Corporate name should not be greater than 100 characters'), + emailAddress: yup + .string() + .email("Invalid email address") + .required("Email address is required") + .min(6, "Email address must be at least 6 characters long") + .max(255, "Email address can be at most 255 characters long") + .test("emailValidity", "Email address is invalid", async function (value) { + if (!value) { + return true; // Allow if the field is empty + } + return await checkEmailValidity(value); + }), + mobileNumber: yup + .string() + .required('Mobile number is required') + // .length(10, 'Mobile number must be exactly 10 digits') + .matches(/^[0-9]+$/, 'Mobile number must be digits only') + .max(15, 'Mobile number corporate must be at most 15 digits'), + ISDcode: yup + .string() + .required('ISD code is required') + .matches(/^\+\d{1,3}$/, 'ISD code must be in the format + followed by 1 to 3 digits'), + }), +} \ No newline at end of file diff --git a/src/validation/corporate/createCorporate.schema.js b/src/validation/corporate/createCorporate.schema.js new file mode 100644 index 0000000..2cd1f98 --- /dev/null +++ b/src/validation/corporate/createCorporate.schema.js @@ -0,0 +1,99 @@ +const yup = require('yup'); +const checkEmailValidity = require('../../utils/helper/emailValidator.helper'); +module.exports = { + body: yup.object().shape({ + full_name_principal: yup + .string() + .required('Full name is required') + .max(100, 'Full name must be at most 100 characters long'), + emailAddress_principal: yup + .string() + .email("Invalid email principal address") + .required("Email address is required") + .max(100, "Email address can be at most 100 characters long") + .test("emailValidity", "Email address pricnipal is invalid", async function (value) { + if (!value) { + return true; // Allow if the field is empty + } + return await checkEmailValidity(value); + }), + ISDCode_principal: yup + .string() + .required('ISD code is required') + .matches(/^\+\d{1,3}$/, 'ISD code must be in the format + followed by 1 to 3 digits'), + mobileNumber_principal: yup + .string() + .required('Mobile number is required') + .matches(/^[0-9]+$/, 'Mobile number must be digits only') + .max(15, 'Mobile number must be at most 15 digits'), + corporate_name: yup + .string() + .required('Corporate name is required') + .max(100, 'Corporate name must be at most 100 characters long'), + industry_xid: yup + .number() + .nullable() + .typeError("Industry ID must be a number") + .positive("Industry ID must be a positive number") + .required('Industry ID is required'), + ISDcode_corporate: yup + .string() + .required('ISD code corporate is required') + .matches(/^\+\d{1,3}$/, 'ISD code corporate must be in the format + followed by 1 to 3 digits'), + mobileNumber_corporate: yup + .string() + .required('Mobile number corporate is required') + .matches(/^[0-9]+$/, 'Mobile number corporate must be digits only') + .max(15, 'Mobile number corporate must be at most 15 digits'), + logo_path_file_name: yup + .string() + .nullable() + .notRequired(), + cin_number: yup + .string() + .max(20, "CIN number must be at most 20 digits"), + pancard_number: yup + .string() + .max(20, "CIN number must be at most 20 digits"), + gst_number: yup + .string() + .max(20, "CIN number must be at most 20 digits"), + gst_file_path_name: yup + .string() + .nullable() + .notRequired(), + pancard_file_path_name: yup + .string() + .nullable() + .notRequired(), + opted_for_expence: yup.boolean().default(false).required('Expence is required'), + opted_for_gifting: yup.boolean().default(false).required('Gifting is required'), + opted_for_benefit: yup.boolean().default(false).required('Benefit is required'), + directors: yup.array().of( + yup.object().shape({ + director_name: yup + .string() + .required('User name is required') + .max(100, 'User name must be at most 100 characters long'), + emailAddress: yup + .string() + .email("Invalid email director address") + .required("Email address is required") + .max(100, "Email address can be at most 100 characters long"), + ISDcode: yup + .string() + .required('ISD code corporate is required') + .matches(/^\+\d{1,3}$/, 'ISD code corporate must be in the format + followed by 1 to 3 digits'), + mobileNumber: yup + .string() + .required('Mobile number corporate is required') + .matches(/^[0-9]+$/, 'Mobile number corporate must be digits only') + .max(15, 'Mobile number corporate must be at most 15 digits'), + pancard_file_path_name: yup + .string() + .notRequired(), + }).optional() + ) + + }), +} \ No newline at end of file diff --git a/src/validation/corporate/index.js b/src/validation/corporate/index.js new file mode 100644 index 0000000..5a2519b --- /dev/null +++ b/src/validation/corporate/index.js @@ -0,0 +1,4 @@ +module.exports = { + corporateQuickAdd: require('./corporateQuickAdd.schema'), + registerWithCode: require('./createCorporate.schema') +} \ No newline at end of file diff --git a/src/validation/fileUpload/all.schema.js b/src/validation/fileUpload/all.schema.js new file mode 100644 index 0000000..1027528 --- /dev/null +++ b/src/validation/fileUpload/all.schema.js @@ -0,0 +1,10 @@ +const yup = require('yup'); +const isValidFileSize = require('../../utils/helper/fileValidator.helper'); + +module.exports = { + file: yup.mixed().test('isFile', 'File size exceeds limit', (value) => { + if (!value) return true; // No attachment provided is allowed. + return isValidFileSize(value); + }).required("Document is equired"), + +} diff --git a/src/validation/fileUpload/index.js b/src/validation/fileUpload/index.js new file mode 100644 index 0000000..ed0318c --- /dev/null +++ b/src/validation/fileUpload/index.js @@ -0,0 +1,3 @@ +module.exports = { + allSchema: require('./all.schema') +} \ No newline at end of file diff --git a/src/validation/icici/index.js b/src/validation/icici/index.js new file mode 100644 index 0000000..ee4d6c0 --- /dev/null +++ b/src/validation/icici/index.js @@ -0,0 +1,3 @@ +module.exports = { + registrationSchema: require('./registration.schema') +} \ No newline at end of file diff --git a/src/validation/icici/registration.schema.js b/src/validation/icici/registration.schema.js new file mode 100644 index 0000000..88c1920 --- /dev/null +++ b/src/validation/icici/registration.schema.js @@ -0,0 +1,99 @@ +const yup = require('yup'); +const checkEmailValidity = require('../../utils/helper/emailValidator.helper'); +module.exports = { + body: yup.object().shape({ + AGGRNAME: yup + .string() + .required('Full name is required') + .max(100, 'Full name must be at most 100 characters long'), + emailAddress_principal: yup + .string() + .email("Invalid email principal address") + .required("Email address is required") + .max(100, "Email address can be at most 100 characters long") + .test("emailValidity", "Email address pricnipal is invalid", async function (value) { + if (!value) { + return true; // Allow if the field is empty + } + return await checkEmailValidity(value); + }), + ISDCode_principal: yup + .string() + .required('ISD code is required') + .matches(/^\+\d{1,3}$/, 'ISD code must be in the format + followed by 1 to 3 digits'), + mobileNumber_principal: yup + .string() + .required('Mobile number is required') + .matches(/^[0-9]+$/, 'Mobile number must be digits only') + .max(15, 'Mobile number must be at most 15 digits'), + corporate_name: yup + .string() + .required('Corporate name is required') + .max(100, 'Corporate name must be at most 100 characters long'), + industry_xid: yup + .number() + .nullable() + .typeError("Industry ID must be a number") + .positive("Industry ID must be a positive number") + .required('Industry ID is required'), + ISDcode_corporate: yup + .string() + .required('ISD code corporate is required') + .matches(/^\+\d{1,3}$/, 'ISD code corporate must be in the format + followed by 1 to 3 digits'), + mobileNumber_corporate: yup + .string() + .required('Mobile number corporate is required') + .matches(/^[0-9]+$/, 'Mobile number corporate must be digits only') + .max(15, 'Mobile number corporate must be at most 15 digits'), + logo_path_file_name: yup + .string() + .nullable() + .notRequired(), + cin_number: yup + .string() + .max(20, "CIN number must be at most 20 digits"), + pancard_number: yup + .string() + .max(20, "CIN number must be at most 20 digits"), + gst_number: yup + .string() + .max(20, "CIN number must be at most 20 digits"), + gst_file_path_name: yup + .string() + .nullable() + .notRequired(), + pancard_file_path_name: yup + .string() + .nullable() + .notRequired(), + opted_for_expence: yup.boolean().default(false).required('Expence is required'), + opted_for_gifting: yup.boolean().default(false).required('Gifting is required'), + opted_for_benefit: yup.boolean().default(false).required('Benefit is required'), + directors: yup.array().of( + yup.object().shape({ + director_name: yup + .string() + .required('User name is required') + .max(100, 'User name must be at most 100 characters long'), + emailAddress: yup + .string() + .email("Invalid email director address") + .required("Email address is required") + .max(100, "Email address can be at most 100 characters long"), + ISDcode: yup + .string() + .required('ISD code corporate is required') + .matches(/^\+\d{1,3}$/, 'ISD code corporate must be in the format + followed by 1 to 3 digits'), + mobileNumber: yup + .string() + .required('Mobile number corporate is required') + .matches(/^[0-9]+$/, 'Mobile number corporate must be digits only') + .max(15, 'Mobile number corporate must be at most 15 digits'), + pancard_file_path_name: yup + .string() + .notRequired(), + }).optional() + ) + + }), +} \ No newline at end of file diff --git a/src/validation/index.js b/src/validation/index.js new file mode 100644 index 0000000..d6989db --- /dev/null +++ b/src/validation/index.js @@ -0,0 +1,3 @@ +module.exports = { + iciciBankAPIVaildation: require('./icici') +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..d6ecc8e --- /dev/null +++ b/yarn.lock @@ -0,0 +1,2022 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@apidevtools/json-schema-ref-parser@^9.0.6": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8" + integrity sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg== + dependencies: + "@jsdevtools/ono" "^7.1.3" + "@types/json-schema" "^7.0.6" + call-me-maybe "^1.0.1" + js-yaml "^4.1.0" + +"@apidevtools/openapi-schemas@^2.0.4": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" + integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== + +"@apidevtools/swagger-methods@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" + integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== + +"@apidevtools/swagger-parser@10.0.3": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz#32057ae99487872c4dd96b314a1ab4b95d89eaf5" + integrity sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g== + dependencies: + "@apidevtools/json-schema-ref-parser" "^9.0.6" + "@apidevtools/openapi-schemas" "^2.0.4" + "@apidevtools/swagger-methods" "^3.0.2" + "@jsdevtools/ono" "^7.1.3" + call-me-maybe "^1.0.1" + z-schema "^5.0.1" + +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + +"@jsdevtools/ono@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" + integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== + +"@mapbox/node-pre-gyp@^1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + +"@onesignal/node-onesignal@^5.0.0-alpha-01": + version "5.0.0-alpha-01" + resolved "https://registry.yarnpkg.com/@onesignal/node-onesignal/-/node-onesignal-5.0.0-alpha-01.tgz#4419e11c58c3208eaede3f88102c477b9eafc186" + integrity sha512-Ed4CwHk6gh7iaettBQ6DLszCWugbT2ldts26HMmcC4b0GQ43riheKpXrf8yuezZppwFF77nYyHOE/JEyRyBBsg== + dependencies: + "@types/node" "^20.12.8" + "@types/node-fetch" "^2.5.7" + btoa "^1.2.1" + es6-promise "^4.2.4" + form-data "^2.5.0" + node-fetch "^2.6.0" + url-parse "^1.4.3" + +"@types/debug@^4.1.8": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== + dependencies: + "@types/ms" "*" + +"@types/json-schema@^7.0.6": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/ms@*": + version "0.7.34" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" + integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== + +"@types/node-fetch@^2.5.7": + version "2.6.11" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + +"@types/node@*": + version "22.5.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44" + integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA== + dependencies: + undici-types "~6.19.2" + +"@types/node@^20.12.8": + version "20.16.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.5.tgz#d43c7f973b32ffdf9aa7bd4f80e1072310fd7a53" + integrity sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA== + dependencies: + undici-types "~6.19.2" + +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + +"@types/validator@^13.7.17": + version "13.12.2" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.2.tgz#760329e756e18a4aab82fc502b51ebdfebbe49f5" + integrity sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +append-field@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" + integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw== + +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +async@^3.2.3: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +aws-ssl-profiles@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz#157dd77e9f19b1d123678e93f120e6f193022641" + integrity sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g== + +axios@^1.7.4, axios@^1.7.5: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +basic-auth@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +bcrypt@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.1.1.tgz#0f732c6dcb4e12e5b70a25e326a72965879ba6e2" + integrity sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.11" + node-addon-api "^5.0.0" + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +btoa@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" + integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +busboy@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +call-me-maybe@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" + integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== + +chokidar@^3.5.2: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + +combined-stream@^1.0.6, combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" + integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q== + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concat-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" + integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== + +dayjs@^1.11.9: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4, debug@^4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +denque@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== + +depd@2.0.0, depd@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-libc@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + +doctrine@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dotenv@^16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + +dottie@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.6.tgz#34564ebfc6ec5e5772272d466424ad5b696484d4" + integrity sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA== + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es6-promise@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +express-rate-limit@^7.3.1: + version "7.4.0" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.4.0.tgz#5db412b8de83fa07ddb40f610c585ac8c1dab988" + integrity sha512-v1204w3cXu5gCDmAvgvzI6qjzZzoMWKnyVDk3ACgfswTQLYiGen+r8w0VnXnGMmzEN/g8fwIQ4JrFFd4ZP6ssg== + +express@^4.19.2: + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.10" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== + dependencies: + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +form-data@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + +generate-function@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== + dependencies: + is-property "^1.0.2" + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +helmet@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" + integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-status@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/http-status/-/http-status-1.7.4.tgz#7bb7f6b511e0bf5e9e20fb5aa00666f09d1f2615" + integrity sha512-c2qSwNtTlHVYAhMj9JpGdyo0No/+DiKXCJ9pHtZ2Yf3QmPnBIytKSRT7BuyIiQ7icXLynavGmxUqkOjSrAuMuA== + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== + +inflection@^1.13.4: + version "1.13.4" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.4.tgz#65aa696c4e2da6225b148d7a154c449366633a32" + integrity sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-property@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +logform@^2.6.0, logform@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.1.tgz#71403a7d8cae04b2b734147963236205db9b3df0" + integrity sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + +long@^5.2.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + +lru.min@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/lru.min/-/lru.min-1.1.1.tgz#146e01e3a183fa7ba51049175de04667d5701f0e" + integrity sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q== + +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^0.5.4: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +moment-timezone@^0.5.43: + version "0.5.45" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.45.tgz#cb685acd56bac10e69d93c536366eb65aa6bcf5c" + integrity sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ== + dependencies: + moment "^2.29.4" + +moment@^2.29.4, moment@^2.30.1: + version "2.30.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" + integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== + +morgan@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== + dependencies: + basic-auth "~2.0.1" + debug "2.6.9" + depd "~2.0.0" + on-finished "~2.3.0" + on-headers "~1.0.2" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multer@^1.4.5-lts.1: + version "1.4.5-lts.1" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.5-lts.1.tgz#803e24ad1984f58edffbc79f56e305aec5cfd1ac" + integrity sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ== + dependencies: + append-field "^1.0.0" + busboy "^1.0.0" + concat-stream "^1.5.2" + mkdirp "^0.5.4" + object-assign "^4.1.1" + type-is "^1.6.4" + xtend "^4.0.0" + +mysql2@^3.10.2: + version "3.11.3" + resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-3.11.3.tgz#8291e6069a0784310846f6437b8527050dfc10c4" + integrity sha512-Qpu2ADfbKzyLdwC/5d4W7+5Yz7yBzCU05YWt5npWzACST37wJsB23wgOSo00qi043urkiRwXtEvJc9UnuLX/MQ== + dependencies: + aws-ssl-profiles "^1.1.1" + denque "^2.1.0" + generate-function "^2.3.1" + iconv-lite "^0.6.3" + long "^5.2.1" + lru.min "^1.0.0" + named-placeholders "^1.1.3" + seq-queue "^0.0.5" + sqlstring "^2.3.2" + +named-placeholders@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.3.tgz#df595799a36654da55dda6152ba7a137ad1d9351" + integrity sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w== + dependencies: + lru-cache "^7.14.1" + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + +node-fetch@^2.6.0, node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +nodemailer@^6.9.14: + version "6.9.15" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.15.tgz#57b79dc522be27e0e47ac16cc860aa0673e62e04" + integrity sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ== + +nodemon@^3.1.4: + version "3.1.7" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.7.tgz#07cb1f455f8bece6a499e0d72b5e029485521a54" + integrity sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ== + dependencies: + chokidar "^3.5.2" + debug "^4" + ignore-by-default "^1.0.1" + minimatch "^3.1.2" + pstree.remy "^1.1.8" + semver "^7.5.3" + simple-update-notifier "^2.0.0" + supports-color "^5.5.0" + touch "^3.1.0" + undefsafe "^2.0.5" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + +object-assign@^4, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== + +pg-connection-string@^2.6.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37" + integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +property-expr@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" + integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +pstree.remy@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" + integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== + +qs@6.13.0, qs@^6.9.4: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.2.2: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +request-ip@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611" + integrity sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +retry-as-promised@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-7.0.4.tgz#9df73adaeea08cb2948b9d34990549dc13d800a2" + integrity sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-stable-stringify@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +scmp@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/scmp/-/scmp-2.1.0.tgz#37b8e197c425bdeb570ab91cc356b311a11f9c9a" + integrity sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q== + +semver@^6.0.0: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +seq-queue@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" + integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q== + +sequelize-pool@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz#210b391af4002762f823188fd6ecfc7413020768" + integrity sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg== + +sequelize@^6.37.3: + version "6.37.3" + resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.37.3.tgz#ed6212029a52c59a18638d2a703da84bc2f81311" + integrity sha512-V2FTqYpdZjPy3VQrZvjTPnOoLm0KudCRXfGWp48QwhyPPp2yW8z0p0sCYZd/em847Tl2dVxJJ1DR+hF+O77T7A== + dependencies: + "@types/debug" "^4.1.8" + "@types/validator" "^13.7.17" + debug "^4.3.4" + dottie "^2.0.6" + inflection "^1.13.4" + lodash "^4.17.21" + moment "^2.29.4" + moment-timezone "^0.5.43" + pg-connection-string "^2.6.1" + retry-as-promised "^7.0.4" + semver "^7.5.4" + sequelize-pool "^7.1.0" + toposort-class "^1.0.1" + uuid "^8.3.2" + validator "^13.9.0" + wkx "^0.5.0" + +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.0: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +simple-update-notifier@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb" + integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w== + dependencies: + semver "^7.5.3" + +sqlstring@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" + integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +swagger-jsdoc@^6.2.8: + version "6.2.8" + resolved "https://registry.yarnpkg.com/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz#6d33d9fb07ff4a7c1564379c52c08989ec7d0256" + integrity sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ== + dependencies: + commander "6.2.0" + doctrine "3.0.0" + glob "7.1.6" + lodash.mergewith "^4.6.2" + swagger-parser "^10.0.3" + yaml "2.0.0-1" + +swagger-parser@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/swagger-parser/-/swagger-parser-10.0.3.tgz#04cb01c18c3ac192b41161c77f81e79309135d03" + integrity sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg== + dependencies: + "@apidevtools/swagger-parser" "10.0.3" + +swagger-ui-dist@>=5.0.0: + version "5.17.14" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz#e2c222e5bf9e15ccf80ec4bc08b4aaac09792fd6" + integrity sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw== + +swagger-ui-express@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz#fb8c1b781d2793a6bd2f8a205a3f4bd6fa020dd8" + integrity sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA== + dependencies: + swagger-ui-dist ">=5.0.0" + +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +tiny-case@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" + integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +toposort-class@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" + integrity sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg== + +toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" + integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== + +touch@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694" + integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + +twilio@^5.2.2: + version "5.3.1" + resolved "https://registry.yarnpkg.com/twilio/-/twilio-5.3.1.tgz#63078b63ce1bad94747c9004f9c8175d9b9fbdbd" + integrity sha512-angX6IpoUcoehtArCJsUqbBklw2df/FgtzjTyx9fRQU/RPZsULMEGYcs4iNqLj486Iz8cxs6iP69990F9KxCMg== + dependencies: + axios "^1.7.4" + dayjs "^1.11.9" + https-proxy-agent "^5.0.0" + jsonwebtoken "^9.0.2" + qs "^6.9.4" + scmp "^2.1.0" + xmlbuilder "^13.0.2" + +type-fest@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + +type-is@^1.6.4, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + +undefsafe@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" + integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +url-parse@^1.4.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +validator@^13.7.0, validator@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" + integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +winston-transport@^4.7.0: + version "4.7.1" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.1.tgz#52ff1bcfe452ad89991a0aaff9c3b18e7f392569" + integrity sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA== + dependencies: + logform "^2.6.1" + readable-stream "^3.6.2" + triple-beam "^1.3.0" + +winston@^3.13.0: + version "3.14.2" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.14.2.tgz#94ce5fd26d374f563c969d12f0cd9c641065adab" + integrity sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.6.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + +wkx@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c" + integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg== + dependencies: + "@types/node" "*" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +xmlbuilder@^13.0.2: + version "13.0.2" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7" + integrity sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ== + +xss-clean@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/xss-clean/-/xss-clean-0.1.4.tgz#592b7f59cc52d39d4b8c397787243817639fb73d" + integrity sha512-4hArTFHYxrifK9VXOu/zFvwjTXVjKByPi6woUHb1IqxlX0Z4xtFBRjOhTKuYV/uE1VswbYsIh5vUEYp7MmoISQ== + dependencies: + xss-filters "1.2.7" + +xss-filters@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/xss-filters/-/xss-filters-1.2.7.tgz#59fa1de201f36f2f3470dcac5f58ccc2830b0a9a" + integrity sha512-KzcmYT/f+YzcYrYRqw6mXxd25BEZCxBQnf+uXTopQDIhrmiaLwO+f+yLsIvvNlPhYvgff8g3igqrBxYh9k8NbQ== + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@2.0.0-1: + version "2.0.0-1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" + integrity sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ== + +yup@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/yup/-/yup-1.4.0.tgz#898dcd660f9fb97c41f181839d3d65c3ee15a43e" + integrity sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg== + dependencies: + property-expr "^2.0.5" + tiny-case "^1.0.3" + toposort "^2.0.2" + type-fest "^2.19.0" + +z-schema@^5.0.1: + version "5.0.6" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" + integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== + dependencies: + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + validator "^13.7.0" + optionalDependencies: + commander "^10.0.0"