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: `
+
+
+
+
+
+
+
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
+
+
+
+
+
+
+
+
+`,
+ };
+ 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"