From c2b7f0bef9ec56843586a2751c211257a6cba3e8 Mon Sep 17 00:00:00 2001 From: DaraSingh1998 Date: Sat, 22 Nov 2025 19:37:47 +0530 Subject: [PATCH 1/4] Temp commit --- .DS_Store | Bin 8196 -> 10244 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index c35309a615e22795526c8f28c2698a56bdecb32d..7d07b1b5b6479f94ac273e0ee046128582d55183 100644 GIT binary patch literal 10244 zcmeHM&ubGw6n>kuX>E#Bd+}iF3W5bmwCGVGwyEHu7Yl;7{4{M%x}j++y+{xb1+RMW z;$I+&=if4E@6Aqk=gsc6J&D-au=_SM-<$c~H?wau6C&~!wp;T=J`s)M zWIHv9OUl9Zd?t>ZF1Z8i!JoRF`ITnS>nD(|z$xGqa0)mDoB~dPe?ptS^~h1pjaKapW+)>U)zed!_cAzhZnlShOVAoVtAoD z%6*NiXgdsT=uVzqe0aKNPp?os)jQhv6`Z_EXx-H*;1ozIz-#vrDpQBnXiKc$#|pD% zT`#Cs8{MFRvhkajKJ0#Of4VK}TZh*7SB<@a2_LRBcF-@a(l#|j?{xlG5@B+frt5F- z-%uQ^c6vd~BpW68P>uPFg3lVYs7-arW$c!$HF@~65f8)PAygA>f=+UbsF65 z22HIur!>~O{97HkBg#_)TsJJ#yL6Nl&C}T5jO6R(C=%Ve8AY;IMxgR;ftnQ120a9~ zj^yUeSlk3wGR(8yqTb{=b0y+wVd8Pm!lZC6YR+4<3GQ8d+PJgy_nuqqGrVLR-T+=1 zNHe03r6{6IbR65!Xc^@-kf5`e*8w7Zq@pXSn0uIO0S!=6rd{e$*BY^(R?HJrHQL}Y zhE~!i*RgyGc(&WX^|@aQ`|U8SRI>O6SkacLU!fA|XJKO1vM^GsKDwa^Xu)})rRKt8 zJe8YvocTqId#aC&;o@Fa+h#1^m!nux+cclaqp&Hl6%bpXa$MJ*_KQUc!;d?7X5a-@w`${znCHNlNm#OaJPBcS~@QKwvu8&k- zWsYK`fqvrC-cKsKo6(=5d$a^StF#PThH@?W^s9_&dK6Ut-A>ci<4lx^m0IRr04v%u zwVQboX=h<#t+Fsun+m$YFBs0Ao3w*`(X?}f%7rFt3oUum)nt1n^H+NjbE_RQBV?l_ zd-b+H2lo87=KNN|DD(So9q}|V24($S1v>k?4xx-Jn!~Uf| z1B^Wh`RlOHv{KjIa`ocY|Io==+gGFg->kL0xl+l($nmK0c)0cdz+49%cP($Ko%Hzw DeLPy# literal 8196 zcmeI1zl#$=6vyA>H+LXGK@LG!IoneYY{k70dohKDO@5jLvbQ-eQ4ot@B^Fj9SlbGg zg0`aNRf3Iw!8Nuv>UVxPd9yz*+K8t!VfXFLdvD$+-_S_3(1cEf)v3a4F@#P>e_-N5 zV;9=$bP{IsAxvdqb|^ws$M}H?ClPAv&t3tqKw1I0cQ4Te8q%0%&i=jp`8)STakJT- z#9j2&Ud4y!_bz_easB-x{nHWqZJ-(;m8w7M(un5Nb*fYSQ96P%oH@7o^3AvRk|8lp z6fa5gqZ}T(E_uq}8B?DI)Nxs=S6naWIA~Z7md_coBi#CJS-(hK)Zb0iez^4Ty3q|= z*W~eiBu>&6~D%B4(+4UQ7nZy5X479q>%>8Q^N) zB@!(VNdCs2Bi{o6M9$T)=F*)C=SeLUcIV<3d)qOQd&g!YRNk8X$_S|wg zV{o3lm<)~+n6U{+rnE&f%w44Z?x^d;YO8F4>&SS{`SG>oT#>U}dB2+Deh;($ Date: Sat, 22 Nov 2025 22:04:53 +0530 Subject: [PATCH 2/4] Added eslint, pritter settings with auto run on save, added rate limitter using redis for prod and memory for others, fixed lint errors in template --- .editorconfig | 32 + .env.development | 11 +- .husky/pre-commit | 4 + .prettierrc | 17 +- .vscode/extensions.json | 7 + .vscode/settings.json | 18 + README.md | 509 +++- app.js | 54 +- config/db.js | 46 +- controllers/v1/general/general.js | 14 +- controllers/v1/index.js | 2 +- docs/README.md | 44 + docs/code-quality.md | 468 ++++ docs/rate-limiter.md | 621 +++++ eslint.config.js | 80 + helper/auth.js | 12 +- helper/casbin-enforcer.js | 31 +- helper/error-handler.js | 27 +- helper/index.js | 14 +- helper/otp-templete.js | 38 +- helper/users.js | 4 +- middleware/auth.js | 8 +- middleware/dispatcher.js | 78 +- middleware/handle-error.js | 16 +- middleware/index.js | 25 +- middleware/logger.js | 151 +- middleware/rate-limiter.js | 141 + middleware/trim.js | 48 +- middleware/validator.js | 43 +- models/casbin_rule.js | 106 +- models/init-models.js | 31 +- models/sys_dropdown_list.js | 98 +- models/sys_otp_template.js | 88 +- models/sys_tables.js | 116 +- package-lock.json | 4185 +++++++++++++++++++++-------- package.json | 28 +- plopfile.js | 164 +- routes/v1/general/general.js | 2 +- routes/v1/general/index.js | 2 +- service/v1/index.js | 3 +- utils/constant.js | 78 +- utils/format-response.js | 107 +- utils/hash.js | 6 +- utils/helper.js | 16 +- utils/logger.js | 95 +- utils/mail.js | 15 +- utils/message-helper.js | 46 +- utils/message.js | 80 +- utils/notifications.js | 36 - utils/search-util.js | 64 +- utils/time.js | 42 +- utils/token.js | 2 +- utils/upload.js | 101 +- 53 files changed, 5961 insertions(+), 2113 deletions(-) create mode 100644 .editorconfig create mode 100755 .husky/pre-commit create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 docs/README.md create mode 100644 docs/code-quality.md create mode 100644 docs/rate-limiter.md create mode 100644 eslint.config.js create mode 100644 middleware/rate-limiter.js delete mode 100644 utils/notifications.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a445467 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +# EditorConfig helps maintain consistent coding styles across different editors and IDEs +# For more information, visit: https://editorconfig.org + +root = true + +# Apply to all files +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +# JavaScript, JSON, and related files +[*.{js,json,yml,yaml}] +indent_style = tab +indent_size = 4 +max_line_length = 100 + +# Markdown files +[*.md] +trim_trailing_whitespace = false +max_line_length = off + +# Package.json and similar files +[package.json] +indent_style = tab +indent_size = 2 + +# YAML files (often prefer spaces) +[*.{yml,yaml}] +indent_style = space +indent_size = 2 diff --git a/.env.development b/.env.development index f7e2de9..cac03db 100644 --- a/.env.development +++ b/.env.development @@ -1,12 +1,17 @@ -DB_HOST="127.0.0.1" +DB_HOST=127.0.0.1 DB_USER="root" DB_PASSWORD="" -DB_NAME="test_db" +DB_NAME=test_db PORT=9000 EMAIL_PORT=465 EMAIL_HOST="smtp.zoho.in" EMAIL_USER="team@thecodebucket.com" EMAIL_PASSWORD="Team$123" -BASEURL=http://localhost:5000/" +BASEURL=http://localhost:5000/ VIRUS_CHECKER=OFF JWT_PRIVATE_KEY=swc_random_string + +# Redis Configuration (for production rate limiting) +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD= diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..d24fdfc --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged diff --git a/.prettierrc b/.prettierrc index 47f2b33..cfc8b7a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,10 +1,11 @@ { - "arrowParens": "avoid", - "tabWidth": 4, - "endOfLine": "auto", - "quoteProps": "consistent", - "jsxBracketSameLine": true, - "useTabs": true, - "printWidth": 100, - "trailingComma": "all" + "arrowParens": "avoid", + "tabWidth": 4, + "endOfLine": "auto", + "quoteProps": "consistent", + "jsxBracketSameLine": true, + "useTabs": true, + "printWidth": 100, + "trailingComma": "all", + "semi": true } diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..913e37b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "editorconfig.editorconfig" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b2dfd51 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,18 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "eslint.validate": ["javascript", "javascriptreact"], + "eslint.alwaysShowStatus": true, + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "[markdown]": { + "files.trimTrailingWhitespace": false + }, + "prettier.requireConfig": true, + "editor.tabSize": 4, + "editor.insertSpaces": false +} diff --git a/README.md b/README.md index d8544e2..7924e06 100644 --- a/README.md +++ b/README.md @@ -1 +1,508 @@ -# node-template \ No newline at end of file +# Node Backend Template + +Production-ready Node.js/Express.js backend template for building scalable, secure APIs with standardized patterns and best practices. + +**Maintained by:** Codebucket Solutions Pvt. Ltd. + +๐Ÿ“š **Documentation**: See [`docs/`](./docs) for detailed usage guides. + +--- + +## ๐Ÿš€ Quick Start + +### Prerequisites + +- Node.js 16+ (Node 20+ recommended) +- MySQL 5.7+ +- Redis (for production rate limiting) + +### Installation + +```bash +# Clone the repository +git clone https://github.com/Codebucket-Solutions/node-template.git +cd node-template + +# Install dependencies +npm install + +# Set up environment +cp .env.development .env.local +# Edit .env.local with your database credentials + +# Run in development mode +npm run start:dev +``` + +The server will start on `http://localhost:9000` (configurable via `PORT` in `.env`). + +--- + +## ๐Ÿ“ Project Structure + +``` +node-template/ +โ”œโ”€โ”€ bin/ +โ”‚ โ””โ”€โ”€ www # Server entry point with clustering +โ”œโ”€โ”€ config/ +โ”‚ โ””โ”€โ”€ db.js # Database configuration +โ”œโ”€โ”€ controllers/ # Request handlers (versioned) +โ”‚ โ””โ”€โ”€ v1/ +โ”œโ”€โ”€ helper/ # Helper utilities +โ”œโ”€โ”€ middleware/ # Express middleware +โ”‚ โ”œโ”€โ”€ auth.js # JWT authentication +โ”‚ โ”œโ”€โ”€ validator.js # Request validation +โ”‚ โ”œโ”€โ”€ dispatcher.js # Permission-based routing +โ”‚ โ”œโ”€โ”€ rate-limiter.js # Rate limiting +โ”‚ โ”œโ”€โ”€ logger.js # Request logging +โ”‚ โ””โ”€โ”€ handle-error.js # Error handling +โ”œโ”€โ”€ models/ # Sequelize models +โ”œโ”€โ”€ routes/ # API routes (versioned) +โ”‚ โ””โ”€โ”€ v1/ +โ”œโ”€โ”€ service/ # Business logic layer +โ”‚ โ””โ”€โ”€ v1/ +โ”œโ”€โ”€ utils/ # Utility functions +โ”œโ”€โ”€ plop-templates/ # Code generation templates +โ”œโ”€โ”€ app.js # Express app configuration +โ””โ”€โ”€ package.json +``` + +--- + +## ๐Ÿ—๏ธ Architecture + +### Layered Architecture + +``` +Request โ†’ Routes โ†’ Middleware โ†’ Controllers โ†’ Services โ†’ Models โ†’ Database +``` + +**Middleware Chain:** + +``` +CORS & Helmet (Security) + โ†“ +Global Rate Limiter + โ†“ +Body Parser + โ†“ +Logger (Pino) + โ†“ +Routes + โ†“ +Authentication & Authorization (Casbin) + โ†“ +Validation (Joi) + โ†“ +Controller + โ†“ +Service Layer + โ†“ +Database (Sequelize ORM) +``` + +### Versioned API Design + +APIs are organized by version for backward compatibility: + +``` +/v1/general/endpoint +/v2/general/endpoint +``` + +--- + +## โœจ Key Features + +### 1. **Rate Limiting** ๐Ÿ›ก๏ธ + +Environment-aware rate limiting with automatic store selection: + +- **Development**: In-memory store (no setup required) +- **Production**: Redis store (distributed rate limiting) + +**Available Limiters:** + +| Limiter | Limit | Window | Use Case | +| --------------- | ------- | ------ | ----------------------------- | +| `globalLimiter` | 100 req | 15 min | All routes (applied globally) | +| `authLimiter` | 5 req | 15 min | Login/auth endpoints | +| `apiLimiter` | 30 req | 1 min | High-traffic endpoints | +| `uploadLimiter` | 10 req | 1 hour | File uploads | + +๐Ÿ“– **[View detailed usage guide โ†’](./docs/rate-limiter.md)** + +### 2. **Authentication & Authorization** ๐Ÿ” + +- **JWT-based authentication** with token validation middleware +- **Casbin RBAC** for fine-grained permission control +- **Dispatcher pattern** for centralized permission checking + +### 3. **Request Validation** โœ… + +Joi-based schema validation middleware for request body, query, and params validation. + +### 4. **Logging** ๐Ÿ“ + +- **Pino** for high-performance structured logging +- **Custom log server transport** (`@codebucket/logserver-transport`) +- Request/response logging with correlation IDs + +### 5. **Database Management** ๐Ÿ—„๏ธ + +- **Sequelize ORM** with MySQL support +- **Transaction support** using CLS (Continuation Local Storage) +- **Model auto-initialization** with migration support +- **Connection pooling** (max 1000 connections) + +### 6. **Security** ๐Ÿ”’ + +- **Helmet.js** - Security headers +- **CORS** - Cross-origin resource sharing +- **Bcrypt** - Password hashing +- **Input trimming** - Automatic whitespace removal +- **ClamAV virus scanning** (optional) +- **Rate limiting** - DDoS protection + +### 7. **Code Quality** ๐Ÿ“ + +- **ESLint** - Code linting and quality checks +- **Prettier** - Automatic code formatting +- **EditorConfig** - Consistent editor settings across IDEs +- **Pre-commit hooks** - Automatic linting before commits +- **IDE integration** - VSCode, WebStorm, and others + +๐Ÿ“– **[View code quality guide โ†’](./docs/code-quality.md)** + +### 8. **Code Generation** โšก + +Built-in Plop.js generators for scaffolding: + +```bash +npm run plop +``` + +**Generates:** + +- Versioned route files +- Controller boilerplate +- Service layer logic + +### 9. **File Upload** ๐Ÿ“ค + +- **Formidable** for multipart form handling +- **AWS S3** integration +- **Virus scanning** support (ClamAV) +- **Upload rate limiting** + +### 10. **Email Notifications** ๐Ÿ“ง + +- **Nodemailer** with Zoho SMTP +- **OTP templates** (`sys_otp_template` model) +- Template-based email rendering + +### 11. **Clustering** ๐Ÿ”„ + +Multi-core support using Node.js cluster module for improved performance and scalability. + +--- + +## ๐Ÿ› ๏ธ Scripts + +```bash +# Development (with auto-reload) +npm run start:dev + +# Production (Node 20+) +npm start + +# Production (Node 16) +npm run start:16 + +# Code generation +npm run plop + +# Testing +npm run test:dev +``` + +--- + +## ๐ŸŒ Environment Variables + +Create `.env.development` or `.env.production`: + +```bash +# Database +DB_HOST=127.0.0.1 +DB_USER=root +DB_PASSWORD=your_password +DB_NAME=your_database + +# Server +PORT=9000 +NODE_ENV=development + +# JWT +JWT_PRIVATE_KEY=your_secret_key + +# Email (Zoho) +EMAIL_HOST=smtp.zoho.in +EMAIL_PORT=465 +EMAIL_USER=your_email@example.com +EMAIL_PASSWORD=your_email_password + +# Redis (Production Rate Limiting) +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD= + +# Optional Features +VIRUS_CHECKER=OFF +BASEURL=http://localhost:9000/ +``` + +--- + +## ๐Ÿ“– Usage Examples + +### Creating a New API Endpoint + +**1. Generate files:** + +```bash +npm run plop +# Select: route, controller, service +# Enter: version=v1, group=products, name=create +``` + +**2. Define model** (`models/products.js`): + +```javascript +module.exports = function (sequelize, DataTypes) { + return sequelize.define("products", { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + name: { type: DataTypes.STRING, allowNull: false }, + price: { type: DataTypes.DECIMAL(10, 2), allowNull: false }, + }); +}; +``` + +**3. Implement service** (`service/v1/products.js`): + +```javascript +const { products } = require("../../models"); + +const createProduct = async data => { + return await products.create(data); +}; + +module.exports = { createProduct }; +``` + +**4. Implement controller** (`controllers/v1/products.js`): + +```javascript +const { createProduct } = require("../../service/v1/products"); + +const create = async (req, res) => { + const product = await createProduct(req.body); + return res.json({ success: true, data: product }); +}; + +module.exports = { create }; +``` + +**5. Define route** (`routes/v1/products/create.js`): + +```javascript +const express = require("express"); +const router = express.Router(); +const { dispatcher, validateToken, apiLimiter } = require("../../../middleware"); +const { create } = require("../../../controllers/v1/products"); +const { PERMS, RESOURCES } = require("../../../utils/constant"); + +router.post("/", validateToken, apiLimiter, (req, res, next) => + dispatcher(req, res, next, create, RESOURCES.PRODUCTS, PERMS.ADD), +); + +module.exports = router; +``` + +--- + +## ๐Ÿณ Docker Deployment + +### Basic Deployment + +```bash +docker build -t node-template . +docker run -p 3000:3000 --env-file .env.production node-template +``` + +### Docker Compose + +```bash +docker-compose up -d +``` + +**Production Setup:** + +- Uses internal registry: `harbor.internal.codebuckets.in` +- NPM registry: `https://npm.internal.codebuckets.in` + +--- + +## ๐Ÿงช Testing Rate Limits + +```bash +# Make multiple requests to test rate limiting +for i in {1..101}; do + curl http://localhost:9000/v1/endpoint +done + +# Check rate limit headers +curl -i http://localhost:9000/v1/endpoint +``` + +**Response Headers:** + +``` +RateLimit-Limit: 100 +RateLimit-Remaining: 99 +RateLimit-Reset: 900 +``` + +**Rate Limit Exceeded (429):** + +```json +{ + "success": false, + "message": "Too many requests from this IP, please try again later." +} +``` + +--- + +## ๐Ÿ”ง Configuration Tips + +### Adjusting Rate Limits + +Edit `middleware/rate-limiter.js`: + +```javascript +const customLimiter = createLimiter({ + windowMs: 10 * 60 * 1000, // 10 minutes + max: 50, // 50 requests + message: { success: false, message: "Custom message" }, + prefix: "rl:custom:", +}); +``` + +### User-Based Rate Limiting + +```javascript +const userLimiter = createLimiter({ + windowMs: 15 * 60 * 1000, + max: 200, + keyGenerator: req => req.user?.id || req.ip, +}); +``` + +### Increasing Worker Processes + +Edit `bin/www`: + +```javascript +const cpu = require("os").cpus().length; +for (let i = 0; i < cpu; i++) { + // Use all CPU cores + cluster.fork(); +} +``` + +--- + +## ๐Ÿ“š System Models + +### Included System Tables + +- **`sys_tables`** - Dynamic table configuration +- **`sys_dropdown_list`** - Dropdown options +- **`sys_otp_template`** - OTP email templates +- **`casbin_rule`** - RBAC policies + +--- + +## ๐ŸŽฏ Best Practices + +โœ… **Always use transactions** for multi-step database operations +โœ… **Apply appropriate rate limiters** to different endpoint types +โœ… **Validate all inputs** using Joi schemas +โœ… **Use Casbin dispatcher** for permission checks +โœ… **Log important events** with proper context +โœ… **Handle errors centrally** using error middleware +โœ… **Use environment variables** for configuration +โœ… **Version your APIs** for backward compatibility +โœ… **Test thoroughly** before production deployment + +--- + +## ๐Ÿค Contributing + +This is an internal template maintained by Codebucket Solutions. For issues or suggestions, please contact the development team. + +--- + +## ๐Ÿ“„ License + +ISC License - Copyright ยฉ Codebucket Solutions Pvt. Ltd. + +--- + +## ๐Ÿ†˜ Troubleshooting + +### Database Connection Refused + +```bash +# Check MySQL is running +mysql.server status + +# Verify credentials in .env +DB_HOST=127.0.0.1 +DB_USER=root +DB_PASSWORD=your_password +``` + +### Redis Connection Failed (Production) + +```bash +# Check Redis is running +redis-cli ping # Should return PONG + +# System will fallback to memory store with warning +``` + +### Rate Limiter Not Working + +- Verify middleware is imported in `app.js` +- Check environment configuration +- Review console logs for initialization messages + +### Port Already in Use + +```bash +# Find process using port 9000 +lsof -ti:9000 | xargs kill -9 + +# Or change PORT in .env +PORT=9001 +``` + +--- + +## ๐Ÿ“ž Support + +For internal support, contact: **team@thecodebucket.com** + +Repository: https://github.com/Codebucket-Solutions/node-template diff --git a/app.js b/app.js index a8845b5..a51f143 100644 --- a/app.js +++ b/app.js @@ -8,7 +8,13 @@ const logger = require("./middleware/logger"); require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` }); require("moment-timezone")().tz("Asia/Kolkata"); -const { validator, validateToken, handleError, trimMiddleware } = require("./middleware"); +const { + validator, + validateToken, + handleError, + trimMiddleware, + globalLimiter, +} = require("./middleware"); console.log(process.env.NODE_ENV); @@ -19,34 +25,36 @@ const app = express(); app.use("/", express.static(path.join(__dirname, "../public"))); -app - .use(cors()) - .use(helmet()) - .use( - bodyParser.urlencoded({ - limit: "100mb", - extended: true, - parameterLimit: 50000, - }) - ) - .use(bodyParser.json({ limit: "100mb" })) - .use(logger) - .use(express.static(path.join(__dirname, "public"))); +app.use(cors()) + .use(helmet()) + .use(globalLimiter) // Rate limiting protection + .use( + bodyParser.urlencoded({ + limit: "100mb", + extended: true, + parameterLimit: 50000, + }), + ) + .use(bodyParser.json({ limit: "100mb" })) + .use(logger) + .use(express.static(path.join(__dirname, "public"))) + .use(validateToken) + .use(validator); app.use(trimMiddleware); app.use("/v1", v1); -app.use((err, req, res, next) => { - handleError(err, res); +app.use((err, req, res) => { + handleError(err, res); }); sequelize - .sync() - .then(() => { - console.log("Database connected"); - }) - .catch((err) => { - throw err; - }); + .sync() + .then(() => { + console.log("Database connected"); + }) + .catch(err => { + throw err; + }); module.exports = app; diff --git a/config/db.js b/config/db.js index eaf7312..698db46 100644 --- a/config/db.js +++ b/config/db.js @@ -6,29 +6,29 @@ const cls = createNamespace("transaction-namespace"); // any string Sequelize.useCLS(cls); const sequelize = new Sequelize( - getOrThrow("DB_NAME"), // Database name - getOrThrow("DB_USER"), // Username - getOrThrow("DB_PASSWORD"), // Password - { - dialect: "mysql", - host: getOrThrow("DB_HOST"), - timezone: "+05:30", - dialectOptions: { - multipleStatements: true, - decimalNumbers: true - }, - define: { - // Prevent Sequelize from pluralizing table names - freezeTableName: true - }, - logging: false, - pool: { - max: 1000, - min: 0, - acquire: 30000, - idle: 10000, - } - } + getOrThrow("DB_NAME"), // Database name + getOrThrow("DB_USER"), // Username + getOrThrow("DB_PASSWORD"), // Password + { + dialect: "mysql", + host: getOrThrow("DB_HOST"), + timezone: "+05:30", + dialectOptions: { + multipleStatements: true, + decimalNumbers: true, + }, + define: { + // Prevent Sequelize from pluralizing table names + freezeTableName: true, + }, + logging: false, + pool: { + max: 1000, + min: 0, + acquire: 30000, + idle: 10000, + }, + }, ); module.exports = sequelize; diff --git a/controllers/v1/general/general.js b/controllers/v1/general/general.js index b50cf8a..33f77b5 100644 --- a/controllers/v1/general/general.js +++ b/controllers/v1/general/general.js @@ -1,13 +1,13 @@ -const sequelize = require("../../../config/db"); +// const sequelize = require("../../../config/db"); const createApi = async (req, res, next) => { - try { - console.log("Create Api"); - } catch (error) { - next(error); - } + try { + console.log("Create Api"); + } catch (error) { + next(error); + } }; module.exports = { - createApi, + createApi, }; diff --git a/controllers/v1/index.js b/controllers/v1/index.js index e8af5a8..a2af03d 100644 --- a/controllers/v1/index.js +++ b/controllers/v1/index.js @@ -1,5 +1,5 @@ const { createApi } = require("./general"); module.exports = { - createApi, + createApi, }; diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..ad3c8a6 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,44 @@ +# Documentation + +This directory contains detailed usage guides and examples for all template features. + +## Available Guides + +### [Code Quality](./code-quality.md) + +Complete guide for ESLint and Prettier setup with IDE integration for: + +- VSCode configuration +- WebStorm configuration +- Pre-commit hooks +- npm scripts for linting and formatting +- CI/CD integration +- Troubleshooting + +### [Rate Limiter](./rate-limiter.md) + +Complete guide for using the environment-aware rate limiting system with examples for: + +- Authentication endpoints +- File uploads +- API endpoints +- Custom rate limiters +- Redis configuration +- Testing and monitoring + +## Coming Soon + +Additional documentation will be added for: + +- Authentication & Authorization (JWT + Casbin) +- Request Validation (Joi schemas) +- Database Operations (Sequelize transactions) +- Code Generation (Plop templates) +- File Uploads (AWS S3 integration) +- Email Notifications +- Error Handling +- Logging + +--- + +For general overview and quick start, see the main [README](../README.md). diff --git a/docs/code-quality.md b/docs/code-quality.md new file mode 100644 index 0000000..d1e34eb --- /dev/null +++ b/docs/code-quality.md @@ -0,0 +1,468 @@ +# Code Quality - Linting and Formatting + +## Overview + +This project uses ESLint and Prettier to maintain consistent code quality and formatting across the codebase, regardless of the IDE or editor used (VSCode, WebStorm, Sublime, etc.). + +## Tools + +- **ESLint**: Code linting and quality checking +- **Prettier**: Code formatting +- **EditorConfig**: Base editor configuration +- **Husky**: Git hooks management +- **lint-staged**: Run linters on staged files + +## Quick Start + +### Install Extensions (Recommended) + +**VSCode:** + +- ESLint (`dbaeumer.vscode-eslint`) +- Prettier (`esbenp.prettier-vscode`) +- EditorConfig (`editorconfig.editorconfig`) + +**WebStorm/IntelliJ:** + +- ESLint (built-in, enable in preferences) +- Prettier (built-in, enable in preferences) +- EditorConfig (built-in support) + +--- + +## Configuration Files + +### `eslint.config.js` + +ESLint v9 flat configuration with: + +- Node.js environment settings +- Prettier integration +- Code quality rules +- Ignores for `node_modules`, `dist`, etc. + +### `.prettierrc` + +Prettier formatting rules: + +- Tab indentation (width: 4) +- 100 character line width +- Trailing commas +- Arrow parentheses avoidance + +### `.editorconfig` + +EditorConfig for basic editor settings: + +- UTF-8 encoding +- LF line endings +- Tab indentation +- Trim trailing whitespace +- Insert final newline + +### `.vscode/settings.json` + +VSCode-specific settings: + +- Auto-format on save +- ESLint auto-fix on save +- Prettier as default formatter + +--- + +## npm Scripts + +### Linting + +```bash +# Check for linting errors +npm run lint + +# Fix auto-fixable linting errors +npm run lint:fix +``` + +### Formatting + +```bash +# Format all files +npm run format + +# Check if files are formatted correctly (CI) +npm run format:check +``` + +--- + +## Usage Examples + +### Manual Linting + +```bash +# Lint entire project +npm run lint + +# Lint specific file +npx eslint path/to/file.js + +# Lint and fix +npx eslint path/to/file.js --fix +``` + +### Manual Formatting + +```bash +# Format entire project +npm run format + +# Format specific file +npx prettier --write path/to/file.js + +# Check formatting without modifying +npx prettier --check "**/*.js" +``` + +### IDE Integration + +**VSCode:** + +1. Install recommended extensions +2. Settings are already configured in `.vscode/settings.json` +3. Code will auto-format on save +4. ES Lint errors will show in Problems panel + +**WebStorm:** + +1. Enable ESLint: `Preferences โ†’ Languages & Frameworks โ†’ JavaScript โ†’ Code Quality Tools โ†’ ESLint โ†’ Enable` +2. Enable Prettier: `Preferences โ†’ Languages & Frameworks โ†’ JavaScript โ†’ Prettier โ†’ Enable` +3. Enable "Run eslint --fix on save" +4. Enable "On save" for Prettier + +--- + +## Pre-commit Hooks + +Git hooks automatically run linting and formatting before each commit. + +### What Happens on Commit: + +1. **lint-staged** runs on staged files +2. **ESLint** fixes issues in `.js` files +3. **Prettier** formats all staged files +4. If errors can't be auto-fixed, commit is blocked + +### Configuration + +**`.husky/pre-commit`**: + +```bash +npx lint-staged +``` + +**`package.json` (`lint-staged` section)**: + +```json +{ + "lint-staged": { + "*.js": ["eslint --fix", "prettier --write"], + "*.{json,md,yml,yaml}": ["prettier --write"] + } +} +``` + +### Bypassing Pre-commit (Emergency Only) + +```bash +# Skip pre-commit hooks (NOT RECOMMENDED) +git commit --no-verify -m "Emergency commit" +``` + +--- + +## ESLint Rules + +### Key Rules Enforced + +| Rule | Description | Auto-fix | +| ---- | ----------- | -------- | + +### Naming Conventions + +| Type | Convention | Example | +| ----------------- | ------------ | ------------------------------ | +| **Files/Folders** | `kebab-case` | `user-controller.js`, `utils/` | + +> **Note:** We strictly enforce `kebab-case` for all file and folder names. + +--- + +| `no-console` | Allow console statements | N/A | +| `no-unused-vars` | Prevent unused variables (prefix with `_` to ignore) | โŒ | +| `prefer-const` | Use `const` for variables that are never reassigned | โœ… | +| `no-var` | Disallow `var`, use `let` or `const` | โœ… | +| `eqeqeq` | Require `===` and `!==` instead of `==` and `!=` | โŒ | +| `curly` | Require curly braces for all control statements | โœ… | +| `no-param-reassign` | Prevent reassigning function parameters | โŒ | +| `prefer-arrow-callback` | Prefer arrow functions for callbacks | โœ… | +| `prettier/prettier` | Enforce Prettier formatting | โœ… | + +### Ignoring Rules + +**Single line:** + +```javascript +// eslint-disable-next-line no-console +console.log("This is allowed"); +``` + +**Entire file:** + +```javascript +/* eslint-disable no-console */ +console.log("File-wide exception"); +``` + +**Specific rule for function:** + +```javascript +/* eslint-disable no-param-reassign */ +function modifyParam(obj) { + obj.modified = true; +} +/* eslint-enable no-param-reassign */ +``` + +**Unused variables (prefix with underscore):** + +```javascript +const { name, _unusedField } = user; // _unusedField won't trigger error +``` + +--- + +## Prettier Formatting + +### Format Rules + +- **Indentation**: Tabs (width: 4) +- **Line width**: 100 characters +- **Quotes**: Double quotes (auto) +- **Semicolons**: Automatic +- **Trailing commas**: Always +- **Arrow parens**: Avoid when possible + +### Example + +**Before:** + +```javascript +function example(a, b, c) { + const result = { name: "John", age: 30 }; + if (a == b) return result; +} +``` + +**After:** + +```javascript +function example(a, b, c) { +\tconst result = { name: 'John', age: 30 }; +\tif (a === b) { +\t\treturn result; +\t} +} +``` + +--- + +## CI/CD Integration + +### GitHub Actions Example + +```yaml +name: Code Quality + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: "20" + - run: npm ci + - run: npm run lint + - run: npm run format:check +``` + +--- + +## Troubleshooting + +### ESLint Not Working in IDE + +**VSCode:** + +1. Check ESLint extension is installed +2. Check "ESLint" appears in status bar +3. Reload window: `Cmd/Ctrl + Shift + P` โ†’ "Reload Window" +4. Check output: `View โ†’ Output โ†’ Select "ESLint"` + +**WebStorm:** + +1. `File โ†’ Invalidate Caches โ†’ Restart` +2. Verify ESLint is enabled in preferences +3. Check "ESLint" in bottom status bar shows green checkmark + +### Format on Save Not Working + +**VSCode:** + +1. Verify `.vscode/settings.json` exists +2. Check `editor.formatOnSave` is `true` +3. Ensure Prettier extension is installed +4. Check file is in workspace (not just opened externally) + +**WebStorm:** + +1. Enable "Actions on Save" in preferences +2. Check "Reformat code" is enabled +3. Verify Prettier is set as default formatter + +### Pre-commit Hook Not Running + +```bash +# Reinstall husky +rm -rf .husky +npm run prepare + +# Make hook executable +chmod +x .husky/pre-commit + +# Test manually +.husky/pre-commit +``` + +### ESLint Errors Can't Be Auto-Fixed + +Some errors require manual fixing: + +1. **Unused variables** - Remove or prefix with `_` +2. **`==` vs `===`** - Change to strict equality +3. **Parameter reassignment** - Refactor code +4. **Undefined variables** - Import or define them + +```bash +# See which errors can be auto-fixed +npm run lint -- --fix-dry-run +``` + +--- + +## Best Practices + +โœ… **Always run linting before committing** (automated via pre-commit) +โœ… **Fix linting errors, don't disable rules** unless absolutely necessary +โœ… **Use consistent formatting** across all files +โœ… **Review lint errors carefully** - they often catch real bugs +โœ… **Keep IDE extensions updated** for best compatibility +โœ… **Follow the configured style guide** (tabs, line width, etc.) +โœ… **Prefix unused parameters with `_`** to avoid errors +โœ… **Use strict equality** (`===`) instead of loose (`==`) + +--- + +## Configuration Reference + +### File Structure + +``` +. +โ”œโ”€โ”€ eslint.config.js # ESLint configuration (v9 flat config) +โ”œโ”€โ”€ .prettierrc # Prettier formatting rules +โ”œโ”€โ”€ .editorconfig # Base editor settings +โ”œโ”€โ”€ .vscode/ +โ”‚ โ”œโ”€โ”€ settings.json # VSCode project settings +โ”‚ โ””โ”€โ”€ extensions.json # Recommended extensions +โ”œโ”€โ”€ .husky/ +โ”‚ โ””โ”€โ”€ pre-commit # Pre-commit hook script +โ””โ”€โ”€ package.json + โ””โ”€โ”€ lint-staged # Staged files configuration +``` + +### Environment Variables + +None required - all configuration is file-based. + +--- + +## Migration Guide + +### From ESLint < 9 + +ESLint v9 uses flat config (`eslint.config.js`) instead of `.eslintrc.*`: + +- โœ… Configuration is JavaScript (more flexible) +- โœ… Single config file (no cascading) +- โœ… Better performance +- โœ… Ignores defined in config (no `.eslintignore` needed) + +### Adding to Existing Project + +1. Install dependencies: + + ```bash + npm install --save-dev eslint eslint-config-prettier eslint-plugin-prettier husky lint-staged + ``` + +2. Copy configuration files: + - `eslint.config.js` + - `.prettierrc` + - `.editorconfig` + - `.vscode/` directory + +3. Initialize git hooks: + + ```bash + npm run prepare + ``` + +4. Fix existing code: + ```bash + npm run lint:fix + npm run format + ``` + +--- + +## Customization + +### Adding Custom ESLint Rules + +Edit `eslint.config.js`: + +```javascript +rules: { + // Add your custom rules + 'no-console': 'warn', // Change to warning instead of off + 'max-len': ['error', { code: 120 }], // Increase max line length +} +``` + +### Changing Prettier Formatting + +Edit `.prettierrc`: + +```json +{ + "tabWidth": 2, // Change to 2 spaces + "useTabs": false, // Use spaces instead of tabs + "printWidth": 120 // Increase line width +} +``` + +--- + +For questions or issues, contact: **team@thecodebucket.com** diff --git a/docs/rate-limiter.md b/docs/rate-limiter.md new file mode 100644 index 0000000..6d1a7d4 --- /dev/null +++ b/docs/rate-limiter.md @@ -0,0 +1,621 @@ +# Rate Limiter - Usage Guide + +## Overview + +The template includes environment-aware rate limiting that automatically switches between: + +- **Development**: In-memory store (no external dependencies) +- **Production**: Redis store (distributed rate limiting across multiple servers) + +## Available Rate Limiters + +### 1. Global Limiter + +```javascript +const { globalLimiter } = require("./middleware"); +``` + +- **Limit**: 100 requests per 15 minutes +- **Applied**: Globally to all routes in `app.js` +- **Purpose**: General API protection against abuse +- **Scope**: Per IP address + +### 2. Auth Limiter + +```javascript +const { authLimiter } = require("./middleware"); +``` + +- **Limit**: 5 requests per 15 minutes +- **Applied**: Login, register, password reset endpoints +- **Purpose**: Prevent brute force attacks +- **Special**: Skips counting successful authentication attempts +- **Scope**: Per IP address + +### 3. API Limiter + +```javascript +const { apiLimiter } = require("./middleware"); +``` + +- **Limit**: 30 requests per minute +- **Applied**: High-traffic or sensitive API endpoints +- **Purpose**: Fine-grained control over specific endpoints +- **Scope**: Per IP address + +### 4. Upload Limiter + +```javascript +const { uploadLimiter } = require("./middleware"); +``` + +- **Limit**: 10 requests per hour +- **Applied**: File upload endpoints +- **Purpose**: Prevent storage abuse and excessive uploads +- **Scope**: Per IP address + +--- + +## Usage Examples + +### Example 1: Protecting Authentication Routes + +**File**: `routes/v1/auth/login.js` + +```javascript +const express = require("express"); +const router = express.Router(); +const { dispatcher, authLimiter } = require("../../../middleware"); +const { login, register, resetPassword, requestOTP } = require("../../../controllers/v1/auth"); +const { PERMS, RESOURCES } = require("../../../utils/constant"); + +// Apply strict rate limiting to all auth routes +router.post("/login", authLimiter, (req, res, next) => + dispatcher(req, res, next, login, RESOURCES.AUTH, PERMS.VIEW), +); + +router.post("/register", authLimiter, (req, res, next) => + dispatcher(req, res, next, register, RESOURCES.AUTH, PERMS.ADD), +); + +router.post("/reset-password", authLimiter, (req, res, next) => + dispatcher(req, res, next, resetPassword, RESOURCES.AUTH, PERMS.EDIT), +); + +router.post("/request-otp", authLimiter, (req, res, next) => + dispatcher(req, res, next, requestOTP, RESOURCES.AUTH, PERMS.VIEW), +); + +module.exports = router; +``` + +### Example 2: File Upload Routes + +**File**: `routes/v1/upload/upload.js` + +```javascript +const express = require("express"); +const router = express.Router(); +const { dispatcher, uploadLimiter, validateToken } = require("../../../middleware"); +const { uploadFile, uploadMultiple } = require("../../../controllers/v1/upload"); +const { PERMS, RESOURCES } = require("../../../utils/constant"); + +// Apply upload rate limiting to prevent abuse +router.post("/single", validateToken, uploadLimiter, (req, res, next) => + dispatcher(req, res, next, uploadFile, RESOURCES.UPLOAD, PERMS.ADD), +); + +router.post("/multiple", validateToken, uploadLimiter, (req, res, next) => + dispatcher(req, res, next, uploadMultiple, RESOURCES.UPLOAD, PERMS.ADD), +); + +module.exports = router; +``` + +### Example 3: Applying Limiter to Entire Route Group + +**File**: `routes/v1/api/data.js` + +```javascript +const express = require("express"); +const router = express.Router(); +const { apiLimiter, validateToken } = require("../../../middleware"); +const { getData, createData, updateData, deleteData } = require("../../../controllers/v1/data"); + +// Apply API limiter to all routes in this router +router.use(apiLimiter); + +// All routes below will have the API rate limiter applied +router.get("/", validateToken, getData); +router.post("/", validateToken, createData); +router.put("/:id", validateToken, updateData); +router.delete("/:id", validateToken, deleteData); + +module.exports = router; +``` + +### Example 4: Multiple Limiters on Same Route + +**File**: `routes/v1/admin/bulk-import.js` + +```javascript +const express = require("express"); +const router = express.Router(); +const { apiLimiter, uploadLimiter, validateToken } = require("../../../middleware"); +const { bulkImport } = require("../../../controllers/v1/admin"); + +// Apply both API limiter AND upload limiter for extra protection +router.post("/", validateToken, apiLimiter, uploadLimiter, bulkImport); + +module.exports = router; +``` + +### Example 5: Conditional Rate Limiting + +**File**: `routes/v1/public/search.js` + +```javascript +const express = require("express"); +const router = express.Router(); +const { apiLimiter, validateToken } = require("../../../middleware"); +const { search } = require("../../../controllers/v1/search"); + +// Apply rate limiter only to unauthenticated requests +router.get( + "/", + (req, res, next) => { + if (!req.headers.authorization) { + return apiLimiter(req, res, next); + } + next(); + }, + search, +); + +module.exports = router; +``` + +--- + +## Configuration + +### Environment Variables + +Add to your `.env.development` or `.env.production`: + +```bash +# Redis Configuration (required for production) +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD= +``` + +### Environment-Based Store Selection + +The rate limiter automatically selects the appropriate store: + +```javascript +// Development (NODE_ENV !== 'production') +// Uses in-memory store +// Limits reset on server restart +// No Redis required + +// Production (NODE_ENV === 'production') +// Uses Redis store +// Limits persist across server restarts +// Shared across multiple server instances +``` + +--- + +## Response Format + +### Successful Request + +**Response Headers:** + +```http +RateLimit-Policy: 100;w=900 +RateLimit-Limit: 100 +RateLimit-Remaining: 99 +RateLimit-Reset: 900 +``` + +- `RateLimit-Limit`: Maximum requests allowed in the window +- `RateLimit-Remaining`: Number of requests remaining +- `RateLimit-Reset`: Seconds until the rate limit resets + +### Rate Limit Exceeded + +**Status Code**: `429 Too Many Requests` + +**Response Body**: + +```json +{ + "success": false, + "message": "Too many requests from this IP, please try again later." +} +``` + +**Response Headers**: + +```http +RateLimit-Limit: 100 +RateLimit-Remaining: 0 +RateLimit-Reset: 523 +Retry-After: 523 +``` + +--- + +## Custom Rate Limiters + +### Creating a Custom Limiter + +**File**: `middleware/rate-limiter.js` + +Add your custom limiter using the `createLimiter` helper: + +```javascript +/** + * Custom limiter for payment endpoints + * 3 requests per 5 minutes + */ +const paymentLimiter = createLimiter({ + windowMs: 5 * 60 * 1000, // 5 minutes + max: 3, // 3 requests per window + message: { + success: false, + message: "Too many payment requests. Please wait before trying again.", + }, + prefix: "rl:payment:", // Redis key prefix + skipSuccessfulRequests: false, + skipFailedRequests: false, +}); + +module.exports = { + globalLimiter, + authLimiter, + apiLimiter, + uploadLimiter, + paymentLimiter, // Export your custom limiter +}; +``` + +Then use it in your routes: + +```javascript +const { paymentLimiter } = require("../../../middleware"); + +router.post("/process-payment", validateToken, paymentLimiter, processPayment); +``` + +### User-Based Rate Limiting + +For authenticated endpoints, rate limit by user ID instead of IP: + +```javascript +const userBasedLimiter = createLimiter({ + windowMs: 15 * 60 * 1000, + max: 200, // Higher limit for authenticated users + keyGenerator: req => { + // Use user ID if authenticated, otherwise fall back to IP + return req.user?.id || req.ip; + }, + message: { + success: false, + message: "Too many requests for this account.", + }, + prefix: "rl:user:", +}); +``` + +### Tiered Rate Limiting + +Different limits based on user subscription tier: + +```javascript +const tieredLimiter = createLimiter({ + windowMs: 15 * 60 * 1000, + max: req => { + if (req.user?.tier === "premium") return 1000; + if (req.user?.tier === "basic") return 100; + return 50; // Anonymous/free users + }, + keyGenerator: req => req.user?.id || req.ip, + message: { + success: false, + message: "Rate limit exceeded. Upgrade to premium for higher limits.", + }, + prefix: "rl:tiered:", +}); +``` + +### Skip Rate Limiting for Admins + +```javascript +const adminExemptLimiter = createLimiter({ + windowMs: 15 * 60 * 1000, + max: 100, + skip: req => { + // Skip rate limiting for admin users + return req.user?.role === "admin" || req.user?.role === "superadmin"; + }, + prefix: "rl:admin-exempt:", +}); +``` + +--- + +## Testing + +### Manual Testing + +**1. Test with curl:** + +```bash +# Single request +curl -i http://localhost:9000/v1/login + +# Multiple requests to trigger rate limit +for i in {1..6}; do + curl -i http://localhost:9000/v1/login -d '{"email":"test@test.com"}' -H "Content-Type: application/json" + sleep 1 +done +``` + +**2. Check rate limit headers:** + +```bash +curl -i http://localhost:9000/v1/endpoint | grep RateLimit +``` + +**3. Test Redis integration (production):** + +```bash +# Set environment and start server +NODE_ENV=production npm start + +# Check Redis keys +redis-cli KEYS "rl:*" + +# Monitor rate limit counters +redis-cli MONITOR +``` + +### Automated Testing + +**File**: `test/rate-limiter.test.js` + +```javascript +const request = require("supertest"); +const app = require("../app"); + +describe("Rate Limiter", () => { + it("should allow requests within limit", async () => { + const res = await request(app).get("/v1/endpoint").expect(200); + + expect(res.headers["ratelimit-remaining"]).toBeDefined(); + }); + + it("should block requests exceeding limit", async () => { + // Make requests up to the limit + for (let i = 0; i < 100; i++) { + await request(app).get("/v1/endpoint"); + } + + // 101st request should be blocked + const res = await request(app).get("/v1/endpoint").expect(429); + + expect(res.body.success).toBe(false); + expect(res.body.message).toContain("Too many requests"); + }); +}); +``` + +--- + +## Monitoring & Debugging + +### Console Logs + +The rate limiter logs initialization messages: + +**Development:** + +``` +Using memory store for rate limiting (development mode) +``` + +**Production (successful):** + +``` +Redis connected for rate limiting +``` + +**Production (fallback):** + +``` +Redis Client Error: [error details] +Using memory store for rate limiting as fallback +``` + +### Redis Monitoring + +```bash +# View all rate limit keys +redis-cli KEYS "rl:*" + +# Monitor real-time operations +redis-cli MONITOR | grep rl: + +# Check specific key +redis-cli GET "rl:global:127.0.0.1" + +# Get TTL (time to live) +redis-cli TTL "rl:global:127.0.0.1" +``` + +### Application Metrics + +Track rate limit metrics in your monitoring system: + +```javascript +const { redisClient } = require("./middleware/rate-limiter"); + +// Monitor rate limit hits +app.use((req, res, next) => { + const remaining = res.getHeader("RateLimit-Remaining"); + if (remaining === "0") { + console.warn("Rate limit hit:", { ip: req.ip, path: req.path }); + // Send to monitoring service (e.g., DataDog, New Relic) + } + next(); +}); +``` + +--- + +## Troubleshooting + +### Rate Limiter Not Working + +**1. Check middleware import:** + +```javascript +const { globalLimiter } = require("./middleware"); +``` + +**2. Verify middleware is applied:** + +```javascript +app.use(globalLimiter); // Should be before routes +``` + +**3. Check console logs:** +Look for initialization messages indicating which store is being used. + +### Redis Connection Issues + +**1. Verify Redis is running:** + +```bash +redis-cli ping # Should return PONG +``` + +**2. Check environment variables:** + +```bash +echo $REDIS_HOST +echo $REDIS_PORT +``` + +**3. Test connection:** + +```bash +redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD ping +``` + +**4. Check firewall/network:** +Ensure Redis port (6379) is accessible from your application server. + +### Rate Limits Not Resetting + +**Development (memory store):** + +- Limits reset on server restart +- Each server instance has its own limits + +**Production (Redis store):** + +```bash +# Check TTL of keys +redis-cli TTL "rl:global:127.0.0.1" + +# Manually clear if needed (use with caution) +redis-cli DEL "rl:global:127.0.0.1" + +# Clear all rate limit keys (emergency only) +redis-cli KEYS "rl:*" | xargs redis-cli DEL +``` + +### Different Behavior Across Instances + +If using multiple server instances without Redis: + +- Each instance maintains its own rate limit counters +- Users could bypass limits by hitting different instances +- **Solution**: Use Redis in production + +--- + +## Best Practices + +โœ… **Apply global limiter** to protect all routes by default +โœ… **Use stricter limits for auth endpoints** to prevent brute force +โœ… **Use Redis in production** for distributed rate limiting +โœ… **Monitor rate limit headers** to understand usage patterns +โœ… **Adjust limits based on requirements** after analyzing usage +โœ… **Test thoroughly** before deploying new rate limits +โœ… **Set up Redis monitoring** to detect connection issues +โœ… **Use custom messages** to guide users on retry timing +โœ… **Consider user-based limiting** for authenticated endpoints +โœ… **Exempt admins/internal services** from strict limits when appropriate + +--- + +## Performance Impact + +- **Memory Store**: ~1ms overhead per request +- **Redis Store**: ~2-5ms overhead per request (depending on network latency) +- **Memory Usage**: ~1KB per unique IP/user per time window +- **Redis Memory**: Automatically expires keys after time window + +--- + +## Security Considerations + +๐Ÿ”’ **IP Spoofing**: Consider using `X-Forwarded-For` in trusted proxy environments +๐Ÿ”’ **Distributed Attacks**: Redis store helps mitigate distributed attacks +๐Ÿ”’ **Application-Level DoS**: Combine with server-level rate limiting (nginx, etc.) +๐Ÿ”’ **Credential Stuffing**: Auth limiter helps prevent automated credential attacks +๐Ÿ”’ **Resource Exhaustion**: Upload limiter prevents storage/bandwidth abuse + +--- + +## Migration Guide + +### Adding Rate Limiting to Existing Routes + +**1. Import the limiter:** + +```javascript +const { apiLimiter } = require("../../../middleware"); +``` + +**2. Add to route definition:** + +```javascript +// Before +router.post("/data", validateToken, createData); + +// After +router.post("/data", validateToken, apiLimiter, createData); +``` + +**3. Test in development first:** + +```bash +npm run start:dev +``` + +**4. Deploy to production with Redis configured:** + +```bash +NODE_ENV=production npm start +``` + +--- + +For questions or issues, contact: **team@thecodebucket.com** diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..3c647b3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,80 @@ +const eslintPluginPrettier = require("eslint-plugin-prettier"); +const eslintConfigPrettier = require("eslint-config-prettier"); +const filenamesSimple = require("eslint-plugin-filenames-simple"); + +module.exports = [ + { + ignores: [ + "node_modules/**", + "coverage/**", + "dist/**", + "build/**", + "**/*.min.js", + ".husky/**", + "models/**", + "middleware/validator.js", + "middleware/dispatcher.js", + "eslint.config.js", + "utils/time.js", + ], + }, + { + files: ["**/*.js"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "commonjs", + globals: { + console: "readonly", + process: "readonly", + __dirname: "readonly", + __filename: "readonly", + module: "readonly", + require: "readonly", + exports: "writable", + Buffer: "readonly", + setTimeout: "readonly", + setInterval: "readonly", + clearTimeout: "readonly", + clearInterval: "readonly", + }, + }, + plugins: { + "prettier": eslintPluginPrettier, + "filenames-simple": filenamesSimple, + }, + rules: { + ...eslintConfigPrettier.rules, + "prettier/prettier": "error", + "no-console": "off", + "no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "no-process-exit": "off", + "prefer-const": "error", + "no-var": "error", + "object-shorthand": "error", + "quote-props": ["error", "as-needed"], + "prefer-template": "error", + "prefer-arrow-callback": "error", + "no-param-reassign": [ + "error", + { + props: false, + }, + ], + "no-unreachable": "error", + "no-undef": "error", + "eqeqeq": ["error", "always"], + "curly": ["error", "all"], + "brace-style": ["error", "1tbs"], + + // Naming Conventions + "filenames-simple/naming-convention": ["error", { rule: "kebab-case" }], + "semi": ["error", "always"], + }, + }, +]; diff --git a/helper/auth.js b/helper/auth.js index 7799c91..26a1fad 100644 --- a/helper/auth.js +++ b/helper/auth.js @@ -2,13 +2,19 @@ const { ErrorHandler } = require("./error-handler"); const { UNAUTHORIZED } = require("./status-codes"); const checkAuth = user => { - if (!user || user.isAuth !== true) throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); + if (!user || user.isAuth !== true) { + throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); + } }; const checkUserType = (user, types) => { if (user.department) { - if (!types.includes(user.department)) throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); - } else if (!types.includes(user.userType)) throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); + if (!types.includes(user.department)) { + throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); + } + } else if (!types.includes(user.userType)) { + throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); + } }; module.exports = { diff --git a/helper/casbin-enforcer.js b/helper/casbin-enforcer.js index 8b62bba..df17cf6 100644 --- a/helper/casbin-enforcer.js +++ b/helper/casbin-enforcer.js @@ -1,20 +1,19 @@ -let casbin = require("casbin"); -let path = require("path"); -let { SequelizeAdapter } = require("casbin-sequelize-adapter"); -let { ROLES, PERMS, RESOURCES } = require("../utils/constant"); +const casbin = require("casbin"); +const path = require("path"); +const { SequelizeAdapter } = require("casbin-sequelize-adapter"); module.exports = (async () => { - const adapter = await SequelizeAdapter.newAdapter({ - username: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_NAME, - host: process.env.DB_HOST, - dialect: "mysql", - }); + const adapter = await SequelizeAdapter.newAdapter({ + username: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + dialect: "mysql", + }); - const enforcer = await casbin.newEnforcer( - path.join(__dirname, "..", "models", "casbin-model.conf"), - adapter - ); + const enforcer = await casbin.newEnforcer( + path.join(__dirname, "..", "models", "casbin-model.conf"), + adapter, + ); - return enforcer; + return enforcer; })(); diff --git a/helper/error-handler.js b/helper/error-handler.js index 89d4a4d..76f5246 100644 --- a/helper/error-handler.js +++ b/helper/error-handler.js @@ -1,9 +1,9 @@ class ErrorHandler extends Error { - constructor(statusCode, message) { - super(); - this.statusCode = statusCode; - this.message = message; - } + constructor(statusCode, message) { + super(); + this.statusCode = statusCode; + this.message = message; + } } /** @@ -11,17 +11,16 @@ class ErrorHandler extends Error { * @param {string} key - The environment variable key. * @returns {string} The environment variable value. */ -const getOrThrow = (key) => { - const value = process.env[key]; +const getOrThrow = key => { + const value = process.env[key]; - if ( value !== "" && !value) { - throw new Error(`Environment variable ${key} is not set.`); - } - return value; + if (value !== "" && !value) { + throw new Error(`Environment variable ${key} is not set.`); + } + return value; }; - module.exports = { - ErrorHandler, - getOrThrow, + ErrorHandler, + getOrThrow, }; diff --git a/helper/index.js b/helper/index.js index e09e5ac..170ea60 100644 --- a/helper/index.js +++ b/helper/index.js @@ -5,11 +5,11 @@ const authHelper = require("./auth"); const casbinEnforcer = require("./casbin-enforcer"); module.exports = { - users, - ErrorHandler, - handleError, - getOrThrow, - statusCodes, - authHelper, - casbinEnforcer, + users, + ErrorHandler, + handleError, + getOrThrow, + statusCodes, + authHelper, + casbinEnforcer, }; diff --git a/helper/otp-templete.js b/helper/otp-templete.js index 4b5ed4f..245d3ca 100644 --- a/helper/otp-templete.js +++ b/helper/otp-templete.js @@ -3,24 +3,24 @@ const { QueryTypes } = require("sequelize"); //To fetch template for otp module.exports = { - /** - * @param {string} templateType - * @returns {string} Message For OTP - */ - fetchOtpTemplate: async (templateType) => { - const [template] = await sequelize.query( - "SELECT * FROM `otp_template` where template_type = ? AND status = ?", - { - type: QueryTypes.SELECT, - replacements: [templateType, "Active"], - } - ); + /** + * @param {string} templateType + * @returns {string} Message For OTP + */ + fetchOtpTemplate: async templateType => { + const [template] = await sequelize.query( + "SELECT * FROM `otp_template` where template_type = ? AND status = ?", + { + type: QueryTypes.SELECT, + replacements: [templateType, "Active"], + }, + ); - return { - DLT: template.dlt, - mailSubject: template.template_email_subject, - mail: template.template_message_email, - phone: template.template_message, - }; - }, + return { + DLT: template.dlt, + mailSubject: template.template_email_subject, + mail: template.template_message_email, + phone: template.template_message, + }; + }, }; diff --git a/helper/users.js b/helper/users.js index 86491a8..f33fa46 100644 --- a/helper/users.js +++ b/helper/users.js @@ -1,4 +1,4 @@ module.exports = { - USER: "user", - ADMIN: "admin", + USER: "user", + ADMIN: "admin", }; diff --git a/middleware/auth.js b/middleware/auth.js index 36a3130..f4b1a38 100644 --- a/middleware/auth.js +++ b/middleware/auth.js @@ -18,7 +18,9 @@ module.exports = function (req, res, next) { let user = { isAuth: false }; req.user = user; - if (!token||token=='null'||token==null) return next(); + if (!token || token === "null" || token === null) { + return next(); + } let decoded; try { @@ -27,7 +29,9 @@ module.exports = function (req, res, next) { return next(err); } - if (!decoded) return next(); + if (!decoded) { + return next(); + } user = { ...user, isAuth: true, ...decoded }; req.user = user; diff --git a/middleware/dispatcher.js b/middleware/dispatcher.js index 7b44610..12ebdc4 100644 --- a/middleware/dispatcher.js +++ b/middleware/dispatcher.js @@ -1,14 +1,8 @@ -const { - statusCodes, - authHelper, - ErrorHandler, - casbinEnforcer, -} = require("../helper"); +const { statusCodes, ErrorHandler, casbinEnforcer } = require("../helper"); const { constant, camelize } = require("../utils"); const { OK, UNAUTHORIZED } = statusCodes; -const { SUCCESS, FAILURE } = constant; -const { checkAuth, checkUserType } = authHelper; +const { SUCCESS } = constant; /** * @@ -25,39 +19,43 @@ const { checkAuth, checkUserType } = authHelper; */ const dispatcher = async (req, res, next, func, resource, perm) => { - try { - const { user } = req; - if (perm) { - let enforcer = await casbinEnforcer; - const checkPerm = await enforcer.enforce( - user.userId, - resource, - perm, - user.role - ); + try { + const { user, body } = req; - if (!checkPerm) throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); - } - const data = await func(req, res, next); - if (data != null) { - if (req.body && req.body.export) { - if (data.data) { - return res.xls( - req.body.fileName ? req.body.fileName : "report.xlsx", - data.data - ); - } else { - return res.xls( - req.body.fileName ? req.body.fileName : "report.xlsx", - data - ); - } - } - return res.status(OK).json({ status: SUCCESS, data: camelize(data) }); - } - } catch (err) { - next(err); - } + const enforcer = await casbinEnforcer; + if (perm) { + const checkPerm = await enforcer.enforce( + String(user.userId), + body.programCode, + perm, + user.role, + ); + + if (!checkPerm) throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); + } else if (body.programCode) { + const permissions = await enforcer.getImplicitPermissionsForUser(`${user.userId}`); + const hasAccess = permissions.some(([sub, obj, act]) => obj === body.programCode); + + if (user.role !== "Admin" && !hasAccess) + throw new ErrorHandler(UNAUTHORIZED, "Unauthorized"); + } + const data = await func(req, res, next); + if (data != null) { + if (req.body && req.body.export) { + if (data.data) { + return res.xls( + req.body.fileName ? req.body.fileName : "report.xlsx", + data.data, + ); + } else { + return res.xls(req.body.fileName ? req.body.fileName : "report.xlsx", data); + } + } + return res.status(OK).json({ status: SUCCESS, data: camelize(data) }); + } + } catch (err) { + next(err); + } }; module.exports = dispatcher; diff --git a/middleware/handle-error.js b/middleware/handle-error.js index 7db2862..3f2acb6 100644 --- a/middleware/handle-error.js +++ b/middleware/handle-error.js @@ -15,15 +15,17 @@ const { BAD_GATEWAY } = statusCodes; */ const handleError = (err, res) => { - const { statusCode = BAD_GATEWAY, message } = err; + const { statusCode = BAD_GATEWAY, message } = err; - if (res.log) res.log.error(err); + if (res.log) { + res.log.error(err); + } - res.status(statusCode).json({ - status: FAILURE, - statusCode, - message, - }); + res.status(statusCode).json({ + status: FAILURE, + statusCode, + message, + }); }; module.exports = handleError; diff --git a/middleware/index.js b/middleware/index.js index 192a62e..2f9067b 100644 --- a/middleware/index.js +++ b/middleware/index.js @@ -1,13 +1,18 @@ -const validateToken = require('./auth') -const validator = require('./validator') -const dispatcher = require('./dispatcher') -const handleError = require('./handle-error') +const validateToken = require("./auth"); +const validator = require("./validator"); +const dispatcher = require("./dispatcher"); +const handleError = require("./handle-error"); const { trimMiddleware } = require("./trim"); +const { globalLimiter, authLimiter, apiLimiter, uploadLimiter } = require("./rate-limiter"); module.exports = { - validateToken, - validator, - dispatcher, - handleError, - trimMiddleware, -} \ No newline at end of file + validateToken, + validator, + dispatcher, + handleError, + trimMiddleware, + globalLimiter, + authLimiter, + apiLimiter, + uploadLimiter, +}; diff --git a/middleware/logger.js b/middleware/logger.js index 5f68739..a798902 100644 --- a/middleware/logger.js +++ b/middleware/logger.js @@ -1,98 +1,97 @@ const { v4: uuidv4 } = require("uuid"); const logger = require("../utils/logger"); const requestLogger = require("pino-http")({ - // Reuse an existing logger instance - logger: logger, + // Reuse an existing logger instance + logger, - // Define a custom request id function - genReqId: function (req, res) { - const existingID = req.id ?? req.headers["x-request-id"]; - if (existingID) return existingID; - const id = uuidv4(); - res.setHeader("X-Request-Id", id); - return id; - }, + // Define a custom request id function + genReqId(req, res) { + const existingID = req.id ?? req.headers["x-request-id"]; + if (existingID) { + return existingID; + } + const id = uuidv4(); + res.setHeader("X-Request-Id", id); + return id; + }, - // Set to `false` to prevent standard serializers from being wrapped. - wrapSerializers: true, + // Set to `false` to prevent standard serializers from being wrapped. + wrapSerializers: true, - // Define a custom logger level - customLogLevel: function (req, res, err) { - if (res.statusCode >= 400 && res.statusCode < 500) { - return "warn"; - } else if (res.statusCode >= 500 || err) { - return "error"; - } else if (res.statusCode >= 300 && res.statusCode < 400) { - return "silent"; - } - return "info"; - }, + // Define a custom logger level + customLogLevel(req, res, err) { + if (res.statusCode >= 400 && res.statusCode < 500) { + return "warn"; + } else if (res.statusCode >= 500 || err) { + return "error"; + } else if (res.statusCode >= 300 && res.statusCode < 400) { + return "silent"; + } + return "info"; + }, - // Define a custom success message - customSuccessMessage: function (req, res) { - if (res.statusCode === 404) { - return `${req.method} ${req.originalUrl} resource not found`; - } - return `${req.method} ${req.originalUrl} ${res.statusCode} completed`; - }, + // Define a custom success message + customSuccessMessage(req, res) { + if (res.statusCode === 404) { + return `${req.method} ${req.originalUrl} resource not found`; + } + return `${req.method} ${req.originalUrl} ${res.statusCode} completed`; + }, - // Define a custom receive message - customReceivedMessage: function (req, res) { - return `request received: ${req.method} ${req.originalUrl}`; - }, + // Define a custom receive message + customReceivedMessage(req) { + return `request received: ${req.method} ${req.originalUrl}`; + }, - // Define a custom error message - customErrorMessage: function (req, res, err) { - return `${req.method} ${req.originalUrl} request errored with status code: ${res.statusCode}`; - }, + // Define a custom error message + customErrorMessage(req, res) { + return `${req.method} ${req.originalUrl} request errored with status code: ${res.statusCode}`; + }, - // Override attribute keys for the log object - customAttributeKeys: { - req: "request", - res: "response", - err: "error", - }, + // Override attribute keys for the log object + customAttributeKeys: { + req: "request", + res: "response", + err: "error", + }, - serializers: { - res(res) { - //here we are adding response body to log + serializers: { + res(res) { + //here we are adding response body to log - const headers = res.headers; - //fastest way to check response body size - //(We do not want to add large response to log) (adjust size accordingly) - if ( - headers["content-length"] && - parseInt(headers["content-length"]) < 1000 - ) { - res.body = res.raw.body; - } + const headers = res.headers; + //fastest way to check response body size + //(We do not want to add large response to log) (adjust size accordingly) + if (headers["content-length"] && parseInt(headers["content-length"]) < 1000) { + res.body = res.raw.body; + } - return res; - }, - }, + return res; + }, + }, - // Define additional custom request properties - customProps: function (req, res) { - return { - requestId: req.id, - user: req.user, - requestBody: req.body, - }; - }, + // Define additional custom request properties + customProps(req) { + return { + requestId: req.id, + user: req.user, + requestBody: req.body, + }; + }, }); const middleware = (req, res, next) => { - let original = res.json; + const original = res.json; - //Adding response body to res object for use in logging (Remove if not required) - res.json = (data) => { - res.body = data; - res.json = original; - res.json(data); - }; + //Adding response body to res object for use in logging (Remove if not required) + res.json = data => { + res.body = data; + res.json = original; + res.json(data); + }; - requestLogger(req, res); - next(); + requestLogger(req, res); + next(); }; module.exports = middleware; diff --git a/middleware/rate-limiter.js b/middleware/rate-limiter.js new file mode 100644 index 0000000..6935fe7 --- /dev/null +++ b/middleware/rate-limiter.js @@ -0,0 +1,141 @@ +const rateLimit = require("express-rate-limit"); + +let RedisStore, redisClient; + +// Conditionally load Redis dependencies only in production +if (process.env.NODE_ENV === "production") { + try { + RedisStore = require("rate-limit-redis").default; + const redis = require("redis"); + + // Create Redis client for production + redisClient = redis.createClient({ + socket: { + host: process.env.REDIS_HOST || "localhost", + port: process.env.REDIS_PORT || 6379, + }, + password: process.env.REDIS_PASSWORD || undefined, + }); + + redisClient.on("error", err => { + console.error("Redis Client Error:", err); + console.warn("Falling back to memory store for rate limiting"); + }); + + redisClient.on("connect", () => { + console.log("Redis connected for rate limiting"); + }); + + // Connect to Redis + redisClient.connect().catch(err => { + console.error("Failed to connect to Redis:", err); + console.warn("Using memory store for rate limiting as fallback"); + }); + } catch (error) { + console.error("Failed to initialize Redis for rate limiting:", error); + console.warn("Using memory store for rate limiting"); + } +} else { + console.log("Using memory store for rate limiting (development mode)"); +} + +/** + * Helper function to create rate limiter with appropriate store + */ +const createLimiter = config => { + const { prefix, ...otherConfig } = config; // Extract prefix separately + + const limiterConfig = { + ...otherConfig, + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers + }; + + // Use Redis store in production if available + if (process.env.NODE_ENV === "production" && redisClient && RedisStore) { + try { + limiterConfig.store = new RedisStore({ + // @ts-expect-error - Known issue: the `call` function is not present in @types/node-redis + sendCommand: (...args) => redisClient.sendCommand(args), + prefix: prefix || "rl:", + }); + } catch (error) { + console.error("Failed to create Redis store, using memory store:", error); + } + } + + return rateLimit(limiterConfig); +}; + +/** + * Global rate limiter for general API protection + * 100 requests per 15 minutes per IP + */ +const globalLimiter = createLimiter({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, + message: { + success: false, + message: "Too many requests from this IP, please try again later.", + }, + skipSuccessfulRequests: false, + skipFailedRequests: false, + prefix: "rl:global:", +}); + +/** + * Strict limiter for authentication endpoints + * 5 requests per 15 minutes per IP + * Skips successful requests to allow legitimate users + */ +const authLimiter = createLimiter({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 5, + message: { + success: false, + message: "Too many authentication attempts, please try again after 15 minutes.", + }, + skipSuccessfulRequests: true, // Don't count successful logins + skipFailedRequests: false, + prefix: "rl:auth:", +}); + +/** + * Moderate limiter for API endpoints + * 30 requests per minute per IP + */ +const apiLimiter = createLimiter({ + windowMs: 1 * 60 * 1000, // 1 minute + max: 30, + message: { + success: false, + message: "Too many requests, please slow down.", + }, + skipSuccessfulRequests: false, + skipFailedRequests: false, + prefix: "rl:api:", +}); + +/** + * File upload limiter + * 10 uploads per hour per IP + */ +const uploadLimiter = createLimiter({ + windowMs: 60 * 60 * 1000, // 1 hour + max: 10, + message: { + success: false, + message: "Too many file uploads, please try again later.", + }, + skipSuccessfulRequests: false, + skipFailedRequests: false, + prefix: "rl:upload:", +}); + +module.exports = { + globalLimiter, + authLimiter, + apiLimiter, + uploadLimiter, + redisClient, // Export for graceful shutdown if needed +}; diff --git a/middleware/trim.js b/middleware/trim.js index 8e1b1b8..4a8ef2e 100644 --- a/middleware/trim.js +++ b/middleware/trim.js @@ -3,10 +3,10 @@ * Handles nested objects, arrays, and primitive values */ const trimMiddleware = (req, res, next) => { - if (req.body) { - req.body = trimObject(req.body); - } - next(); + if (req.body) { + req.body = trimObject(req.body); + } + next(); }; /** @@ -14,20 +14,20 @@ const trimMiddleware = (req, res, next) => { * @param value - The value to trim (string, array, or object) * @returns The trimmed value */ -const trimValue = (value) => { - if (typeof value === "string") { - return value.trim(); - } +const trimValue = value => { + if (typeof value === "string") { + return value.trim(); + } - if (Array.isArray(value)) { - return value.map(trimValue); - } + if (Array.isArray(value)) { + return value.map(trimValue); + } - if (typeof value === "object" && value !== null) { - return trimObject(value); - } + if (typeof value === "object" && value !== null) { + return trimObject(value); + } - return value; + return value; }; /** @@ -35,17 +35,17 @@ const trimValue = (value) => { * @param obj - The object to process * @returns A new object with all string values trimmed */ -const trimObject = (obj) => { - if (typeof obj !== "object" || obj === null) { - return obj; - } +const trimObject = obj => { + if (typeof obj !== "object" || obj === null) { + return obj; + } - return Object.entries(obj).reduce((acc, [key, value]) => { - acc[key] = trimValue(value); - return acc; - }, {}); + return Object.entries(obj).reduce((acc, [key, value]) => { + acc[key] = trimValue(value); + return acc; + }, {}); }; module.exports = { - trimMiddleware, + trimMiddleware, }; diff --git a/middleware/validator.js b/middleware/validator.js index b06bcec..2ca9ea4 100644 --- a/middleware/validator.js +++ b/middleware/validator.js @@ -22,27 +22,30 @@ const schemas = {}; */ const validator = (req, res, next) => { - console.log(req.path); - try { - const key = `${req.path - .split("/") - .splice(2) - .join("_") - .split("-") - .join("_")}_${req.method.toLowerCase()}`; + console.log(req.path); + try { + const key = `${req.path + .split("/") + .splice(2) + .join("_") + .split("-") + .join("_")}_${req.method.toLowerCase()}`; - const schema = schemas[key]; - console.log({ key: key }); - if (schema === undefined) { - return next(); - } else { - const { value, error } = schema.validate(req.body); - if (error) throw new ErrorHandler(BAD_GATEWAY, error.message); - else next(); - } - } catch (error) { - next(error); - } + const schema = schemas[key]; + console.log({ key }); + if (schema === undefined) { + return next(); + } else { + const { value, error } = schema.validate(req.body); + if (error) { + throw new ErrorHandler(BAD_GATEWAY, error.message); + } else { + next(); + } + } + } catch (error) { + next(error); + } }; module.exports = validator; diff --git a/models/casbin_rule.js b/models/casbin_rule.js index f0ed8c8..00d9771 100644 --- a/models/casbin_rule.js +++ b/models/casbin_rule.js @@ -1,53 +1,55 @@ -const Sequelize = require('sequelize'); -module.exports = function(sequelize, DataTypes) { - return sequelize.define('casbin_rule', { - id: { - autoIncrement: true, - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true - }, - ptype: { - type: DataTypes.STRING(255), - allowNull: true - }, - v0: { - type: DataTypes.STRING(255), - allowNull: true - }, - v1: { - type: DataTypes.STRING(255), - allowNull: true - }, - v2: { - type: DataTypes.STRING(255), - allowNull: true - }, - v3: { - type: DataTypes.STRING(255), - allowNull: true - }, - v4: { - type: DataTypes.STRING(255), - allowNull: true - }, - v5: { - type: DataTypes.STRING(255), - allowNull: true - } - }, { - sequelize, - tableName: 'casbin_rule', - timestamps: false, - indexes: [ - { - name: "PRIMARY", - unique: true, - using: "BTREE", - fields: [ - { name: "id" }, - ] - }, - ] - }); +const Sequelize = require("sequelize"); +module.exports = function (sequelize, DataTypes) { + return sequelize.define( + "casbin_rule", + { + id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + }, + ptype: { + type: DataTypes.STRING(255), + allowNull: true, + }, + v0: { + type: DataTypes.STRING(255), + allowNull: true, + }, + v1: { + type: DataTypes.STRING(255), + allowNull: true, + }, + v2: { + type: DataTypes.STRING(255), + allowNull: true, + }, + v3: { + type: DataTypes.STRING(255), + allowNull: true, + }, + v4: { + type: DataTypes.STRING(255), + allowNull: true, + }, + v5: { + type: DataTypes.STRING(255), + allowNull: true, + }, + }, + { + sequelize, + tableName: "casbin_rule", + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [{ name: "id" }], + }, + ], + }, + ); }; diff --git a/models/init-models.js b/models/init-models.js index a63dcb4..6eb3648 100644 --- a/models/init-models.js +++ b/models/init-models.js @@ -1,22 +1,21 @@ -let DataTypes = require("sequelize").DataTypes; -let _casbin_rule = require("./casbin_rule"); -let _sys_dropdown_list = require("./sys_dropdown_list"); -let _sys_otp_template = require("./sys_otp_template"); -let _sys_tables = require("./sys_tables"); +const DataTypes = require("sequelize").DataTypes; +const _casbin_rule = require("./casbin_rule"); +const _sys_dropdown_list = require("./sys_dropdown_list"); +const _sys_otp_template = require("./sys_otp_template"); +const _sys_tables = require("./sys_tables"); function initModels(sequelize) { - var casbin_rule = _casbin_rule(sequelize, DataTypes); - var sys_dropdown_list = _sys_dropdown_list(sequelize, DataTypes); - var sys_otp_template = _sys_otp_template(sequelize, DataTypes); - var sys_tables = _sys_tables(sequelize, DataTypes); + const casbin_rule = _casbin_rule(sequelize, DataTypes); + const sys_dropdown_list = _sys_dropdown_list(sequelize, DataTypes); + const sys_otp_template = _sys_otp_template(sequelize, DataTypes); + const sys_tables = _sys_tables(sequelize, DataTypes); - - return { - casbin_rule, - sys_dropdown_list, - sys_otp_template, - sys_tables, - }; + return { + casbin_rule, + sys_dropdown_list, + sys_otp_template, + sys_tables, + }; } module.exports = initModels; module.exports.initModels = initModels; diff --git a/models/sys_dropdown_list.js b/models/sys_dropdown_list.js index 021e3f1..236ac2b 100644 --- a/models/sys_dropdown_list.js +++ b/models/sys_dropdown_list.js @@ -1,49 +1,51 @@ -const Sequelize = require('sequelize'); -module.exports = function(sequelize, DataTypes) { - return sequelize.define('sys_dropdown_list', { - id: { - autoIncrement: true, - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true - }, - program_code: { - type: DataTypes.STRING(20), - allowNull: true - }, - dropdown_code: { - type: DataTypes.STRING(50), - allowNull: true - }, - query: { - type: DataTypes.TEXT, - allowNull: true - }, - order_by: { - type: DataTypes.TEXT, - allowNull: true - }, - status: { - type: DataTypes.TEXT, - allowNull: true - }, - conditions: { - type: DataTypes.TEXT, - allowNull: true - } - }, { - sequelize, - tableName: 'sys_dropdown_list', - timestamps: false, - indexes: [ - { - name: "PRIMARY", - unique: true, - using: "BTREE", - fields: [ - { name: "id" }, - ] - }, - ] - }); +const Sequelize = require("sequelize"); +module.exports = function (sequelize, DataTypes) { + return sequelize.define( + "sys_dropdown_list", + { + id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + }, + program_code: { + type: DataTypes.STRING(20), + allowNull: true, + }, + dropdown_code: { + type: DataTypes.STRING(50), + allowNull: true, + }, + query: { + type: DataTypes.TEXT, + allowNull: true, + }, + order_by: { + type: DataTypes.TEXT, + allowNull: true, + }, + status: { + type: DataTypes.TEXT, + allowNull: true, + }, + conditions: { + type: DataTypes.TEXT, + allowNull: true, + }, + }, + { + sequelize, + tableName: "sys_dropdown_list", + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [{ name: "id" }], + }, + ], + }, + ); }; diff --git a/models/sys_otp_template.js b/models/sys_otp_template.js index 39a597f..8d9137e 100644 --- a/models/sys_otp_template.js +++ b/models/sys_otp_template.js @@ -1,44 +1,46 @@ -const Sequelize = require('sequelize'); -module.exports = function(sequelize, DataTypes) { - return sequelize.define('sys_otp_template', { - template_type: { - type: DataTypes.STRING(150), - allowNull: false, - primaryKey: true - }, - template_message: { - type: DataTypes.TEXT, - allowNull: false - }, - template_message_email: { - type: DataTypes.TEXT, - allowNull: true - }, - template_email_subject: { - type: DataTypes.TEXT, - allowNull: false - }, - dlt: { - type: DataTypes.STRING(150), - allowNull: false - }, - status: { - type: DataTypes.STRING(50), - allowNull: false - } - }, { - sequelize, - tableName: 'sys_otp_template', - timestamps: false, - indexes: [ - { - name: "PRIMARY", - unique: true, - using: "BTREE", - fields: [ - { name: "template_type" }, - ] - }, - ] - }); +const Sequelize = require("sequelize"); +module.exports = function (sequelize, DataTypes) { + return sequelize.define( + "sys_otp_template", + { + template_type: { + type: DataTypes.STRING(150), + allowNull: false, + primaryKey: true, + }, + template_message: { + type: DataTypes.TEXT, + allowNull: false, + }, + template_message_email: { + type: DataTypes.TEXT, + allowNull: true, + }, + template_email_subject: { + type: DataTypes.TEXT, + allowNull: false, + }, + dlt: { + type: DataTypes.STRING(150), + allowNull: false, + }, + status: { + type: DataTypes.STRING(50), + allowNull: false, + }, + }, + { + sequelize, + tableName: "sys_otp_template", + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [{ name: "template_type" }], + }, + ], + }, + ); }; diff --git a/models/sys_tables.js b/models/sys_tables.js index e09b52b..f926f4f 100644 --- a/models/sys_tables.js +++ b/models/sys_tables.js @@ -1,58 +1,60 @@ -const Sequelize = require('sequelize'); -module.exports = function(sequelize, DataTypes) { - return sequelize.define('sys_tables', { - id: { - autoIncrement: true, - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true - }, - service_type: { - type: DataTypes.STRING(36), - allowNull: false - }, - section_id: { - type: DataTypes.STRING(36), - allowNull: true - }, - sub_section_id: { - type: DataTypes.STRING(36), - allowNull: true - }, - table_name: { - type: DataTypes.STRING(36), - allowNull: true - }, - multi_table: { - type: DataTypes.JSON, - allowNull: true - }, - status: { - type: DataTypes.ENUM('Active','Inactive'), - allowNull: false, - defaultValue: "Active" - }, - created_by: { - type: DataTypes.STRING(36), - allowNull: true - }, - view_query: { - type: DataTypes.TEXT, - allowNull: false - } - }, { - sequelize, - tableName: 'sys_tables', - timestamps: false, - indexes: [ - { - name: "PRIMARY", - unique: true, - using: "BTREE", - fields: [ - { name: "id" }, - ] - }, - ] - }); +const Sequelize = require("sequelize"); +module.exports = function (sequelize, DataTypes) { + return sequelize.define( + "sys_tables", + { + id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + }, + service_type: { + type: DataTypes.STRING(36), + allowNull: false, + }, + section_id: { + type: DataTypes.STRING(36), + allowNull: true, + }, + sub_section_id: { + type: DataTypes.STRING(36), + allowNull: true, + }, + table_name: { + type: DataTypes.STRING(36), + allowNull: true, + }, + multi_table: { + type: DataTypes.JSON, + allowNull: true, + }, + status: { + type: DataTypes.ENUM("Active", "Inactive"), + allowNull: false, + defaultValue: "Active", + }, + created_by: { + type: DataTypes.STRING(36), + allowNull: true, + }, + view_query: { + type: DataTypes.TEXT, + allowNull: false, + }, + }, + { + sequelize, + tableName: "sys_tables", + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [{ name: "id" }], + }, + ], + }, + ); }; diff --git a/package-lock.json b/package-lock.json index 1aa095a..fc2e839 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "crypto": "^1.0.1", "dotenv": "^16.0.3", "express": "^4.18.2", + "express-rate-limit": "^8.2.1", "formidable": "^2.1.1", "helmet": "^6.0.1", "humps": "^2.0.1", @@ -32,14 +33,23 @@ "jsonwebtoken": "^9.0.0", "moment-timezone": "^0.5.40", "mysql2": "^3.1.0", - "nodemailer": "^6.9.1", + "nodemailer": "^7.0.10", "pino": "^8.20.0", "pino-http": "^9.0.0", "pino-pretty": "^11.0.0", + "rate-limit-redis": "^4.3.0", + "redis": "^5.10.0", "sequelize": "^6.28.0", "uuid": "^9.0.0" }, "devDependencies": { + "eslint": "^9.39.1", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-filenames-simple": "^0.9.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^5.5.4", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", "plop": "^3.1.1", "prettier": "^3.5.3" } @@ -354,674 +364,706 @@ "kuler": "^2.0.0" } }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">= 8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">= 8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, "engines": { - "node": ">= 8" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@sideway/address": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", - "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", - "license": "BSD-3-Clause", + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@hapi/hoek": "^9.0.0" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "license": "BSD-3-Clause" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { - "@types/ms": "*" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@types/fined": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@types/fined/-/fined-1.1.5.tgz", - "integrity": "sha512-2N93vadEGDFhASTIRbizbl4bNqpMOId5zZfj6hHqYZfEzEfO9onnU4Im8xvzo8uudySDveDHBOOSlTWf38ErfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/inquirer": { - "version": "8.2.10", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.10.tgz", - "integrity": "sha512-IdD5NmHyVjWM8SHWo/kPBgtzXatwPkfwzyP3fN1jF2g9BWt5WO+8hL2F4o2GKIYsU40PpqeevuUWvkS/roXJkA==", + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "@types/through": "*", - "rxjs": "^7.2.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@types/liftoff": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/liftoff/-/liftoff-4.0.3.tgz", - "integrity": "sha512-UgbL2kR5pLrWICvr8+fuSg0u43LY250q7ZMkC+XKC3E+rs/YBDEnQIzsnhU5dYsLlwMi3R75UvCL87pObP1sxw==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@types/fined": "*", - "@types/node": "*" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, - "node_modules/@types/node": { - "version": "22.13.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", - "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/through": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", - "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@types/node": "*" + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "license": "MIT" - }, - "node_modules/@types/validator": { - "version": "13.12.2", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz", - "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==", - "license": "MIT" - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "event-target-shim": "^5.0.0" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=6.5" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">= 0.6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 14" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "ms": "^2.1.3" }, "engines": { - "node": ">=8" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "type-fest": "^0.21.3" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "*" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@eslint/js": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/ansi-styles/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "color-name": "~1.1.4" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=7.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/ansi-styles/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } }, - "node_modules/array-each": { + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "node_modules/array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "dev": true, "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT" - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/async-hook-jl": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", - "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "dependencies": { - "stack-chain": "^1.3.7" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^4.7 || >=6.9 || >=7.3" + "node": ">= 8" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8.0.0" + "node": ">= 8" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "license": "MIT", "dependencies": { - "possible-typed-array-names": "^1.0.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 8" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/pkgr" } }, - "node_modules/await-lock": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", - "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", - "license": "MIT" + "node_modules/@redis/bloom": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.10.0.tgz", + "integrity": "sha512-doIF37ob+l47n0rkpRNgU8n4iacBlKM9xLiP1LtTZTvz8TloJB8qx/MgvhMhKdYG+CvCY2aPBnN2706izFn/4A==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" + } }, - "node_modules/aws-sdk": { - "version": "2.1692.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", - "integrity": "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==", - "hasInstallScript": true, - "license": "Apache-2.0", + "node_modules/@redis/client": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.10.0.tgz", + "integrity": "sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA==", + "license": "MIT", "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.6.2" + "cluster-key-slot": "1.1.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">= 18" } }, - "node_modules/aws-sdk/node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "node_modules/@redis/json": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.10.0.tgz", + "integrity": "sha512-B2G8XlOmTPUuZtD44EMGbtoepQG34RCDXLZbjrtON1Djet0t5Ri7/YPXvL9aomXqP8lLTreaprtyLKF4tmXEEA==", "license": "MIT", "engines": { - "node": ">=0.4.x" + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" } }, - "node_modules/aws-sdk/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "node_modules/@redis/search": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.10.0.tgz", + "integrity": "sha512-3SVcPswoSfp2HnmWbAGUzlbUPn7fOohVu2weUQ0S+EMiQi8jwjL+aN2p6V3TI65eNfVsJ8vyPvqWklm6H6esmg==", "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" } }, - "node_modules/aws-ssl-profiles": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", - "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "node_modules/@redis/time-series": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.10.0.tgz", + "integrity": "sha512-cPkpddXH5kc/SdRhF0YG0qtjL+noqFT0AcHbQ6axhsPsO7iqPi1cjxgdkE9TNeKiBUUdCaU1DbqkR/LzbzPBhg==", "license": "MIT", "engines": { - "node": ">= 6.0.0" + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" } }, - "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "@types/ms": "*" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "node_modules/@types/fined": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@types/fined/-/fined-1.1.5.tgz", + "integrity": "sha512-2N93vadEGDFhASTIRbizbl4bNqpMOId5zZfj6hHqYZfEzEfO9onnU4Im8xvzo8uudySDveDHBOOSlTWf38ErfQ==", + "dev": true, "license": "MIT" }, - "node_modules/bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "node_modules/@types/inquirer": { + "version": "8.2.10", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.10.tgz", + "integrity": "sha512-IdD5NmHyVjWM8SHWo/kPBgtzXatwPkfwzyP3fN1jF2g9BWt5WO+8hL2F4o2GKIYsU40PpqeevuUWvkS/roXJkA==", "dev": true, "license": "MIT", "dependencies": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@types/through": "*", + "rxjs": "^7.2.0" } }, - "node_modules/bl/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/liftoff": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/liftoff/-/liftoff-4.0.3.tgz", + "integrity": "sha512-UgbL2kR5pLrWICvr8+fuSg0u43LY250q7ZMkC+XKC3E+rs/YBDEnQIzsnhU5dYsLlwMi3R75UvCL87pObP1sxw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "@types/fined": "*", + "@types/node": "*" } }, - "node_modules/bl/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/@types/node": { + "version": "22.13.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", + "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/through": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", + "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "@types/node": "*" } }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@types/validator": { + "version": "13.12.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz", + "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==", + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", "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" + "event-target-shim": "^5.0.0" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=6.5" } }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=8" + "node": ">=0.4.0" } }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 14" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "type-fest": "^0.21.3" }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "license": "MIT", - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "license": "MIT", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1029,835 +1071,1828 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", - "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansi-styles/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ansi-styles/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/async-hook-jl": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", + "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "license": "MIT", + "dependencies": { + "stack-chain": "^1.3.7" + }, + "engines": { + "node": "^4.7 || >=6.9 || >=7.3" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/await-lock": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", + "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", + "license": "MIT" + }, + "node_modules/aws-sdk": { + "version": "2.1692.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", + "integrity": "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "license": "MIT", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "license": "MIT" + }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bl/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "license": "MIT", + "dependencies": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/casbin": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/casbin/-/casbin-5.38.0.tgz", + "integrity": "sha512-0VI0j18XtftaMj3nnv6CM3h0EvtB8IWPdxWD1t1myyUBOUboMSsMrU9PUtYFX9oAAXRpY2DWNTF1mXUG+QcYvw==", + "license": "Apache-2.0", + "dependencies": { + "@casbin/expression-eval": "^5.3.0", + "await-lock": "^2.0.1", + "buffer": "^6.0.3", + "csv-parse": "^5.5.6", + "minimatch": "^7.4.2" + } + }, + "node_modules/casbin-sequelize-adapter": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/casbin-sequelize-adapter/-/casbin-sequelize-adapter-2.7.1.tgz", + "integrity": "sha512-0ujq7IKumsFk+e/JfmslDaojDRcfYzJh2t6N4aiUW7xpARargw90ac6hoCgX2daePBsufK4giCymQFCN1lycyA==", + "dependencies": { + "reflect-metadata": "^0.1.13", + "sequelize": "6.29.3", + "sequelize-typescript": "^2.1.6" + }, + "peerDependencies": { + "casbin": "<=5.9.0 || >5.9.1" + } + }, + "node_modules/casbin-sequelize-adapter/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/casbin-sequelize-adapter/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/casbin-sequelize-adapter/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/casbin-sequelize-adapter/node_modules/sequelize": { + "version": "6.29.3", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.3.tgz", + "integrity": "sha512-iLbrN//Eh18zXIlNEUNQx7lk5R+SF39m+66bnrT3x8WB8sbxMH2hF4vw8RIa9ZzB1+c94rclMv/i8fngXmb/4A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/sequelize" + } + ], "license": "MIT", "dependencies": { - "camelcase": "^6.3.0", - "map-obj": "^4.1.0", - "quick-lru": "^5.1.1", - "type-fest": "^1.2.1" + "@types/debug": "^4.1.7", + "@types/validator": "^13.7.1", + "debug": "^4.3.3", + "dottie": "^2.0.2", + "inflection": "^1.13.2", + "lodash": "^4.17.21", + "moment": "^2.29.1", + "moment-timezone": "^0.5.35", + "pg-connection-string": "^2.5.0", + "retry-as-promised": "^7.0.3", + "semver": "^7.3.5", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.7.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "snowflake-sdk": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/casbin-sequelize-adapter/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/casbin/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/casbin/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/clamscan": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/clamscan/-/clamscan-2.4.0.tgz", + "integrity": "sha512-XBOxUiGOcQGuKmCn5qaM5rIK153fGCwsvJMbjVtcnNJ+j/YHrSj2gKNjyP65yr/E8JsKTTDtKYFG++p7Lzigyw==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/capital-case": { + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", - "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "license": "BSD-2-Clause", + "dependencies": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "engines": { + "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", "dev": true, "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" + "upper-case": "^2.0.2" } }, - "node_modules/casbin": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/casbin/-/casbin-5.38.0.tgz", - "integrity": "sha512-0VI0j18XtftaMj3nnv6CM3h0EvtB8IWPdxWD1t1myyUBOUboMSsMrU9PUtYFX9oAAXRpY2DWNTF1mXUG+QcYvw==", - "license": "Apache-2.0", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { - "@casbin/expression-eval": "^5.3.0", - "await-lock": "^2.0.1", - "buffer": "^6.0.3", - "csv-parse": "^5.5.6", - "minimatch": "^7.4.2" + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/casbin-sequelize-adapter": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/casbin-sequelize-adapter/-/casbin-sequelize-adapter-2.7.1.tgz", - "integrity": "sha512-0ujq7IKumsFk+e/JfmslDaojDRcfYzJh2t6N4aiUW7xpARargw90ac6hoCgX2daePBsufK4giCymQFCN1lycyA==", + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", "dependencies": { - "reflect-metadata": "^0.1.13", - "sequelize": "6.29.3", - "sequelize-typescript": "^2.1.6" + "object-assign": "^4", + "vary": "^1" }, - "peerDependencies": { - "casbin": "<=5.9.0 || >5.9.1" + "engines": { + "node": ">= 0.10" } }, - "node_modules/casbin-sequelize-adapter/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.", + "license": "ISC" + }, + "node_modules/csv-parse": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.6.0.tgz", + "integrity": "sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q==", + "license": "MIT" + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "ms": "2.0.0" } }, - "node_modules/casbin-sequelize-adapter/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, "license": "MIT" }, - "node_modules/casbin-sequelize-adapter/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/casbin-sequelize-adapter/node_modules/sequelize": { - "version": "6.29.3", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.3.tgz", - "integrity": "sha512-iLbrN//Eh18zXIlNEUNQx7lk5R+SF39m+66bnrT3x8WB8sbxMH2hF4vw8RIa9ZzB1+c94rclMv/i8fngXmb/4A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/sequelize" - } - ], + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "license": "MIT", "dependencies": { - "@types/debug": "^4.1.7", - "@types/validator": "^13.7.1", - "debug": "^4.3.3", - "dottie": "^2.0.2", - "inflection": "^1.13.2", - "lodash": "^4.17.21", - "moment": "^2.29.1", - "moment-timezone": "^0.5.35", - "pg-connection-string": "^2.5.0", - "retry-as-promised": "^7.0.3", - "semver": "^7.3.5", - "sequelize-pool": "^7.1.0", - "toposort-class": "^1.0.1", - "uuid": "^8.3.2", - "validator": "^13.7.0", - "wkx": "^0.5.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "ibm_db": { - "optional": true - }, - "mariadb": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "oracledb": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-hstore": { - "optional": true - }, - "snowflake-sdk": { - "optional": true - }, - "sqlite3": { - "optional": true - }, - "tedious": { - "optional": true - } - } - }, - "node_modules/casbin-sequelize-adapter/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/casbin/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "engines": { + "node": ">=8" } }, - "node_modules/casbin/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", "dev": true, "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/change-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", - "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "node_modules/del/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { - "camel-case": "^4.1.2", - "capital-case": "^1.0.4", - "constant-case": "^3.0.4", - "dot-case": "^3.0.4", - "header-case": "^2.0.4", - "no-case": "^3.0.4", - "param-case": "^3.0.4", - "pascal-case": "^3.1.2", - "path-case": "^3.0.4", - "sentence-case": "^3.0.4", - "snake-case": "^3.0.4", - "tslib": "^2.0.3" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/clamscan": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/clamscan/-/clamscan-2.4.0.tgz", - "integrity": "sha512-XBOxUiGOcQGuKmCn5qaM5rIK153fGCwsvJMbjVtcnNJ+j/YHrSj2gKNjyP65yr/E8JsKTTDtKYFG++p7Lzigyw==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", "engines": { - "node": ">=16.0.0" + "node": ">=0.4.0" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": ">=0.10" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "license": "MIT", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=0.10.0" } }, - "node_modules/clone": { + "node_modules/dezalgo": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" } }, - "node_modules/cls-hooked": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", - "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", - "license": "BSD-2-Clause", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", "dependencies": { - "async-hook-jl": "^1.7.6", - "emitter-listener": "^1.0.1", - "semver": "^5.4.1" + "path-type": "^4.0.0" }, "engines": { - "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1" + "node": ">=8" } }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "node_modules/dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==", "license": "MIT" }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "license": "MIT" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "license": "MIT", + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" + "safe-buffer": "^5.0.1" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "license": "BSD-2-Clause", "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" + "shimmer": "^1.2.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, - "node_modules/constant-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", - "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case": "^2.0.2" - } + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "once": "^1.4.0" } }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4" } }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "es-errors": "^1.3.0" }, "engines": { - "node": ">= 8" + "node": ">= 0.4" } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">= 8" + "node": ">= 0.4" } }, - "node_modules/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", - "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.", - "license": "ISC" - }, - "node_modules/csv-parse": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.6.0.tgz", - "integrity": "sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q==", + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, - "node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=0.8.0" } }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node_modules/eslint": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "dependencies": { - "clone": "^1.0.2" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8.10.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "node_modules/eslint-plugin-filenames-simple": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-filenames-simple/-/eslint-plugin-filenames-simple-0.9.0.tgz", + "integrity": "sha512-eIs+fIO/YXjjlNRdMK3H2HiF0BJ6zj3Of1+REBMnHMbqqgxX1VReIV/gf+ZfP3/bbCAHk5PE3SXi7Fjt3uzUGw==", + "dev": true, "license": "MIT", + "dependencies": { + "pluralize": "^8.0.0" + }, "engines": { - "node": ">=8" + "node": ">=14.17.0" + }, + "peerDependencies": { + "eslint": ">=7.0.0 <9.0.0" } }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, "license": "MIT", "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "engines": { - "node": ">=10" + "node": ">=8.10.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "eslint": ">=5.16.0" } }, - "node_modules/del/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/eslint-plugin-node/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-node/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "*" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/eslint-plugin-node/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "dev": true, "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, "engines": { - "node": ">=0.4.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } } }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "license": "Apache-2.0", + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=0.10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=4" } }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "license": "ISC", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { - "path-type": "^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { - "url": "https://dotenvx.com" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dottie": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", - "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==", - "license": "MIT" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">=10.13.0" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", "dependencies": { - "safe-buffer": "^5.0.1" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "node_modules/eslint/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, - "node_modules/emitter-listener": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", - "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { - "shimmer": "^1.2.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">= 0.8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", + "estraverse": "^5.1.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=0.10" } }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "es-errors": "^1.3.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" + "node": ">=4.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=0.8.0" + "node": ">=0.10.0" } }, "node_modules/etag": { @@ -1878,6 +2913,13 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -1946,6 +2988,24 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-rate-limit": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", + "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "license": "MIT", + "dependencies": { + "ip-address": "10.0.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -1953,27 +3013,26 @@ "dev": true, "license": "MIT" }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fast-copy": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -1991,6 +3050,20 @@ "node": ">=8.6.0" } }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-redact": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", @@ -2038,6 +3111,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -2069,6 +3155,23 @@ "node": ">= 0.8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/findup-sync": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", @@ -2112,6 +3215,27 @@ "node": ">= 10.13.0" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", @@ -2177,13 +3301,15 @@ } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -2191,13 +3317,13 @@ } }, "node_modules/formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", - "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.5.tgz", + "integrity": "sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q==", "license": "MIT", "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", "dezalgo": "^1.0.4", - "hexoid": "^1.0.0", "once": "^1.4.0", "qs": "^6.11.0" }, @@ -2256,6 +3382,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", @@ -2329,9 +3468,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -2384,6 +3523,19 @@ "node": ">=0.10.0" } }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globby": { "version": "13.2.2", "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", @@ -2541,18 +3693,9 @@ }, "node_modules/help-me": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", - "license": "MIT" - }, - "node_modules/hexoid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", - "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", - "license": "MIT", - "engines": { - "node": ">=8" - } + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" }, "node_modules/homedir-polyfill": { "version": "1.0.3", @@ -2661,6 +3804,22 @@ "integrity": "sha512-E0eIbrFWUhwfXJmsbdjRQFQPrl5pTEoKlz163j1mTqqUnU9PgR4AgB8AIITzuB3vLBdxZXyZ9TDIrwB2OASz4g==", "license": "MIT" }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2689,6 +3848,33 @@ "node": ">= 4" } }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -2733,17 +3919,17 @@ "license": "ISC" }, "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "version": "8.2.7", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz", + "integrity": "sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==", "dev": true, "license": "MIT", "dependencies": { + "@inquirer/external-editor": "^1.0.0", "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", - "external-editor": "^3.0.3", "figures": "^3.0.0", "lodash": "^4.17.21", "mute-stream": "0.0.8", @@ -2902,6 +4088,15 @@ "node": ">= 0.10" } }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -3272,6 +4467,19 @@ "node": ">=10" } }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsep": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/jsep/-/jsep-0.3.5.tgz", @@ -3281,6 +4489,27 @@ "node": ">= 6.0.0" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -3363,6 +4592,16 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -3379,6 +4618,20 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", "license": "MIT" }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/liftoff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-4.0.0.tgz", @@ -3399,6 +4652,150 @@ "node": ">=10.13.0" } }, + "node_modules/lint-staged": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -3449,27 +4846,217 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, - "node_modules/log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "node_modules/log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" + "ansi-regex": "^6.0.1" }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/logform": { @@ -3673,6 +5260,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", @@ -3788,6 +5388,26 @@ "node": ">=12.0.0" } }, + "node_modules/nano-spawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -3841,9 +5461,9 @@ } }, "node_modules/nodemailer": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", - "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.10.tgz", + "integrity": "sha512-Us/Se1WtT0ylXgNFfyFSx4LElllVLJXQjWi2Xz17xWw7amDKO2MLtFnVp1WACy7GkVGs+oBlRopVNUzlrGSw1w==", "license": "MIT-0", "engines": { "node": ">=6.0.0" @@ -3985,6 +5605,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/ora": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.1.tgz", @@ -4071,14 +5709,36 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-map": { @@ -4108,6 +5768,19 @@ "tslib": "^2.0.3" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -4164,6 +5837,16 @@ "tslib": "^2.0.3" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -4247,6 +5930,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pino": { "version": "8.21.0", "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", @@ -4363,6 +6059,16 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -4372,6 +6078,16 @@ "node": ">= 0.4" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prettier": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", @@ -4388,6 +6104,19 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -4510,6 +6239,18 @@ "node": ">= 0.6" } }, + "node_modules/rate-limit-redis": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rate-limit-redis/-/rate-limit-redis-4.3.0.tgz", + "integrity": "sha512-rUQSWhoHrpyiYRev0+fTnaCmoZ8F5QAAxPCpVlvlkjNZzY2P4V4KfMPSd1M0Hi0CaRFzydN5ZOyc0HR793Qx5g==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "express-rate-limit": ">= 6" + } + }, "node_modules/raw-body": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", @@ -4607,12 +6348,41 @@ "node": ">= 10.13.0" } }, + "node_modules/redis": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-5.10.0.tgz", + "integrity": "sha512-0/Y+7IEiTgVGPrLFKy8oAEArSyEJkU0zvgV5xyi9NzNQ+SLZmyFbUsWIbgPcd4UdUh00opXGKlXJwMmsis5Byw==", + "license": "MIT", + "dependencies": { + "@redis/bloom": "5.10.0", + "@redis/client": "5.10.0", + "@redis/json": "5.10.0", + "@redis/search": "5.10.0", + "@redis/time-series": "5.10.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/reflect-metadata": { "version": "0.1.14", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", "license": "Apache-2.0" }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -4648,6 +6418,16 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -4679,6 +6459,13 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -4959,9 +6746,9 @@ } }, "node_modules/sequelize-typescript/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -5208,6 +6995,52 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -5315,6 +7148,16 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5381,6 +7224,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -5413,19 +7272,6 @@ "tslib": "^2.0.3" } }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5469,6 +7315,19 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-fest": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", @@ -5553,6 +7412,26 @@ "tslib": "^2.0.3" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -5615,9 +7494,9 @@ } }, "node_modules/validator": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", - "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "version": "13.15.23", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz", + "integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -5748,6 +7627,16 @@ "@types/node": "*" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -5797,6 +7686,32 @@ "engines": { "node": ">=4.0" } + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 8a01e6b..bade7c5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,12 @@ "start:16": "node --loader @codebucket/azure-env ./bin/www", "start": "node --import @codebucket/azure-env ./bin/www", "start:dev": "cross-env NODE_ENV=development nodemon ./bin/www", - "test:dev": "set NODE_ENV=development&&mocha test/*.js --exit" + "test:dev": "set NODE_ENV=development&&mocha test/*.js --exit", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "format": "prettier --write \"**/*.{js,json,md,yml,yaml}\"", + "format:check": "prettier --check \"**/*.{js,json,md,yml,yaml}\"", + "prepare": "husky install" }, "repository": { "type": "git", @@ -37,6 +42,7 @@ "crypto": "^1.0.1", "dotenv": "^16.0.3", "express": "^4.18.2", + "express-rate-limit": "^8.2.1", "formidable": "^2.1.1", "helmet": "^6.0.1", "humps": "^2.0.1", @@ -44,15 +50,33 @@ "jsonwebtoken": "^9.0.0", "moment-timezone": "^0.5.40", "mysql2": "^3.1.0", - "nodemailer": "^6.9.1", + "nodemailer": "^7.0.10", "pino": "^8.20.0", "pino-http": "^9.0.0", "pino-pretty": "^11.0.0", + "rate-limit-redis": "^4.3.0", + "redis": "^5.10.0", "sequelize": "^6.28.0", "uuid": "^9.0.0" }, "devDependencies": { + "eslint": "^9.39.1", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-filenames-simple": "^0.9.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^5.5.4", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", "plop": "^3.1.1", "prettier": "^3.5.3" + }, + "lint-staged": { + "*.js": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,md,yml,yaml}": [ + "prettier --write" + ] } } diff --git a/plopfile.js b/plopfile.js index 3db652f..004f1fb 100644 --- a/plopfile.js +++ b/plopfile.js @@ -1,87 +1,87 @@ module.exports = function (plop) { - // create your generators here + // create your generators here - plop.setGenerator("route", { - description: "application route logic", - prompts: [ - { - type: "input", - name: "version", - message: "Please enter version name", - }, - { - type: "input", - name: "group", - message: "Please enter group name", - }, - { - type: "input", - name: "name", - message: "Please enter route name", - }, - ], - actions: [ - { - type: "add", - path: "routes/{{version}}/{{group}}/{{name}}.js", - templateFile: "plop-templates/route.hbs", - }, - ], - }); + plop.setGenerator("route", { + description: "application route logic", + prompts: [ + { + type: "input", + name: "version", + message: "Please enter version name", + }, + { + type: "input", + name: "group", + message: "Please enter group name", + }, + { + type: "input", + name: "name", + message: "Please enter route name", + }, + ], + actions: [ + { + type: "add", + path: "routes/{{version}}/{{group}}/{{name}}.js", + templateFile: "plop-templates/route.hbs", + }, + ], + }); - plop.setGenerator("controller", { - description: "application controller logic", - prompts: [ - { - type: "input", - name: "version", - message: "Please enter version name", - }, - { - type: "input", - name: "group", - message: "Please enter group name", - }, - { - type: "input", - name: "name", - message: "Please enter controller name", - }, - ], - actions: [ - { - type: "add", - path: "controllers/{{version}}/{{group}}/{{name}}.js", - templateFile: "plop-templates/controller.hbs", - }, - ], - }); + plop.setGenerator("controller", { + description: "application controller logic", + prompts: [ + { + type: "input", + name: "version", + message: "Please enter version name", + }, + { + type: "input", + name: "group", + message: "Please enter group name", + }, + { + type: "input", + name: "name", + message: "Please enter controller name", + }, + ], + actions: [ + { + type: "add", + path: "controllers/{{version}}/{{group}}/{{name}}.js", + templateFile: "plop-templates/controller.hbs", + }, + ], + }); - plop.setGenerator("service", { - description: "application service logic", - prompts: [ - { - type: "input", - name: "version", - message: "Please enter version name", - }, - { - type: "input", - name: "name", - message: "Please enter file name", - }, - { - type: "input", - name: "serviceName", - message: "Please enter service name", - }, - ], - actions: [ - { - type: "add", - path: "service/{{version}}/{{name}}.js", - templateFile: "plop-templates/service.hbs", - }, - ], - }); + plop.setGenerator("service", { + description: "application service logic", + prompts: [ + { + type: "input", + name: "version", + message: "Please enter version name", + }, + { + type: "input", + name: "name", + message: "Please enter file name", + }, + { + type: "input", + name: "serviceName", + message: "Please enter service name", + }, + ], + actions: [ + { + type: "add", + path: "service/{{version}}/{{name}}.js", + templateFile: "plop-templates/service.hbs", + }, + ], + }); }; diff --git a/routes/v1/general/general.js b/routes/v1/general/general.js index 7c3ccba..3daaca3 100644 --- a/routes/v1/general/general.js +++ b/routes/v1/general/general.js @@ -7,7 +7,7 @@ const { createApi } = require("../../../controllers/v1"); const { PERMS, RESOURCES } = require("../../../utils/constant"); router.post("/", (req, res, next) => - dispatcher(req, res, next, createApi, RESOURCES.TEMP, PERMS.ADD) + dispatcher(req, res, next, createApi, RESOURCES.TEMP, PERMS.ADD), ); module.exports = router; diff --git a/routes/v1/general/index.js b/routes/v1/general/index.js index 9ed51f4..56b622d 100644 --- a/routes/v1/general/index.js +++ b/routes/v1/general/index.js @@ -1,5 +1,5 @@ const general = require("./general"); module.exports = { - general, + general, }; diff --git a/service/v1/index.js b/service/v1/index.js index 217617e..ab6bfc4 100644 --- a/service/v1/index.js +++ b/service/v1/index.js @@ -1,4 +1,3 @@ - module.exports = { - // ReplaceWithService + // ReplaceWithService }; diff --git a/utils/constant.js b/utils/constant.js index b91c151..ab56264 100644 --- a/utils/constant.js +++ b/utils/constant.js @@ -1,41 +1,41 @@ module.exports = { - ACTIVE: "Active", - PENDING: "Pending", - INACTIVE: "Inactive", - LOCKED: "Locked", - SALT_ROUNDS: 10, - ALREADY_EXISTS: "Email id/phone already exists.", - ALREADY_EXISTS_MAPPING: "Mapping already exists", - INVALID_CREDENTIALS: "Invalid credentials", - DUPLICATE: "Already exists", - OTP_SENT: "OTP sent successfully", - OTP_EXPIRE: 5, - USER_NOT_FOUND: "User not found", - NOT_FOUND: "Not found", - OTP_VERIFIED: "OTP verified successfully", - INVALID_OTP: "Invalid OTP", - APPLICANT: "APP", - OTP_REGISTRATION_SUBJECT: "OTP for verification", - SUCCESS: "success", - FORGOT_PASSWORD: "Forgot Password", - UPDATE_NUMBER: "Update Number", - PASSWORD_CHANGED: "Password changed successfully", - PHONE: "phone", - MESSAGE_TEMPLATE_TYPES: { - REGISTRATION_OTP: "REGISTRATION_OTP", - LOGIN: "LOGIN", - FORGOT_PASSWORD: "FORGOT_PASSWORD", - REGISTRATION_SUCCESS: "REGISTRATION_SUCCESS", - }, - RESOURCES: { - TEMP: "TEMP_RESOURCE", - }, - PERMS: { - ADD: "ADD", - EDIT: "EDIT", - VIEW: "VIEW", - DELETE: "DELETE", - EXPORT: "EXPORT", - PROCESS: "PROCESS", - }, + ACTIVE: "Active", + PENDING: "Pending", + INACTIVE: "Inactive", + LOCKED: "Locked", + SALT_ROUNDS: 10, + ALREADY_EXISTS: "Email id/phone already exists.", + ALREADY_EXISTS_MAPPING: "Mapping already exists", + INVALID_CREDENTIALS: "Invalid credentials", + DUPLICATE: "Already exists", + OTP_SENT: "OTP sent successfully", + OTP_EXPIRE: 5, + USER_NOT_FOUND: "User not found", + NOT_FOUND: "Not found", + OTP_VERIFIED: "OTP verified successfully", + INVALID_OTP: "Invalid OTP", + APPLICANT: "APP", + OTP_REGISTRATION_SUBJECT: "OTP for verification", + SUCCESS: "success", + FORGOT_PASSWORD: "Forgot Password", + UPDATE_NUMBER: "Update Number", + PASSWORD_CHANGED: "Password changed successfully", + PHONE: "phone", + MESSAGE_TEMPLATE_TYPES: { + REGISTRATION_OTP: "REGISTRATION_OTP", + LOGIN: "LOGIN", + FORGOT_PASSWORD: "FORGOT_PASSWORD", + REGISTRATION_SUCCESS: "REGISTRATION_SUCCESS", + }, + RESOURCES: { + TEMP: "TEMP_RESOURCE", + }, + PERMS: { + ADD: "ADD", + EDIT: "EDIT", + VIEW: "VIEW", + DELETE: "DELETE", + EXPORT: "EXPORT", + PROCESS: "PROCESS", + }, }; diff --git a/utils/format-response.js b/utils/format-response.js index eb41cb2..88759c7 100644 --- a/utils/format-response.js +++ b/utils/format-response.js @@ -2,66 +2,53 @@ const _ = require("lodash"); const { LINK, TEXT, S3_BUCKET_ENDPOINT } = require("./constant"); -const formatResponse = (response) => { - const indexMap = new Map(); - - let mFormattedResponse = response.map((v) => { - const { - coords, - uri, - type, - uuid, - link_title, - link_img, - parent_id, - updated_at, - id, - } = v; - return { - id: uuid, - type, - parent_id, - updated_at, - idd: id, - data: { - link_title, - link_img, - coords, - uri: `${type == LINK || type == TEXT ? "" : S3_BUCKET_ENDPOINT}${uri}`, - }, - }; - }); - - mFormattedResponse.forEach((v, index) => { - const { parent_id } = v; - - if (parent_id && parent_id.length > 0) { - let mParentIndex; - if (indexMap.has(parent_id)) mParentIndex = indexMap.get(parent_id); - else { - mParentIndex = mFormattedResponse.findIndex( - (v1) => v1 && v1.id == parent_id - ); - indexMap.set(parent_id, mParentIndex); - } - - if (mFormattedResponse[mParentIndex]["children"] === undefined) - mFormattedResponse[mParentIndex].children = [v]; - else mFormattedResponse[mParentIndex].children.unshift(v); - - delete mFormattedResponse[index]; - } - }); - - // _.sortBy(mFormattedResponse, ['updated_at']) - mFormattedResponse = _.compact(mFormattedResponse); - mFormattedResponse = _.orderBy( - mFormattedResponse, - [(obj) => new Date(obj.updated_at)], - ["desc"] - ); - - return mFormattedResponse; +const formatResponse = response => { + const indexMap = new Map(); + + let mFormattedResponse = response.map(v => { + const { coords, uri, type, uuid, link_title, link_img, parent_id, updated_at, id } = v; + return { + id: uuid, + type, + parent_id, + updated_at, + idd: id, + data: { + link_title, + link_img, + coords, + uri: `${type === LINK || type === TEXT ? "" : S3_BUCKET_ENDPOINT}${uri}`, + }, + }; + }); + + mFormattedResponse.forEach((v, index) => { + const { parent_id } = v; + + if (parent_id && parent_id.length > 0) { + let mParentIndex; + if (indexMap.has(parent_id)) { + mParentIndex = indexMap.get(parent_id); + } else { + mParentIndex = mFormattedResponse.findIndex(v1 => v1 && v1.id === parent_id); + indexMap.set(parent_id, mParentIndex); + } + + if (mFormattedResponse[mParentIndex]["children"] === undefined) { + mFormattedResponse[mParentIndex].children = [v]; + } else { + mFormattedResponse[mParentIndex].children.unshift(v); + } + + delete mFormattedResponse[index]; + } + }); + + // _.sortBy(mFormattedResponse, ['updated_at']) + mFormattedResponse = _.compact(mFormattedResponse); + mFormattedResponse = _.orderBy(mFormattedResponse, [obj => new Date(obj.updated_at)], ["desc"]); + + return mFormattedResponse; }; module.exports = formatResponse; diff --git a/utils/hash.js b/utils/hash.js index a3b535a..5a6613f 100644 --- a/utils/hash.js +++ b/utils/hash.js @@ -6,7 +6,7 @@ module.exports = { const saltRounds = 10; const hashedPassword = await new Promise((resolve, reject) => { - bcrypt.hash(password, saltRounds, function (err, hash) { + bcrypt.hash(password, saltRounds, (err, hash) => { if (err) { return reject(err instanceof Error ? err : new Error(err)); } @@ -20,8 +20,8 @@ module.exports = { } }, compare: async (original, password) => { - return new Promise(function (resolve, reject) { - bcrypt.compare(password, original, function (err, isMatch) { + return new Promise((resolve, reject) => { + bcrypt.compare(password, original, (err, isMatch) => { if (err) { return reject(err instanceof Error ? err : new Error(err)); } else { diff --git a/utils/helper.js b/utils/helper.js index adfdfe0..cb4e2c7 100644 --- a/utils/helper.js +++ b/utils/helper.js @@ -3,12 +3,12 @@ const { ErrorHandler } = require("../helper"); const { SERVER_ERROR } = require("../helper/status-codes"); module.exports = { - zeroPad: (num, places) => String(num).padStart(places, "0"), - camelize: (obj) => { - try { - return camelcaseKeys(JSON.parse(JSON.stringify(obj)), { deep: true }); - } catch (error) { - throw new ErrorHandler(SERVER_ERROR, error); - } - }, + zeroPad: (num, places) => String(num).padStart(places, "0"), + camelize: obj => { + try { + return camelcaseKeys(JSON.parse(JSON.stringify(obj)), { deep: true }); + } catch (error) { + throw new ErrorHandler(SERVER_ERROR, error); + } + }, }; diff --git a/utils/logger.js b/utils/logger.js index 5512b40..d6669ef 100644 --- a/utils/logger.js +++ b/utils/logger.js @@ -1,71 +1,70 @@ const pino = require("pino"); -let { - NODE_ENV, - LOGSERVER_APPLICATION, - LOGSERVER_SERVICE, - LOGSERVER_ENVIRONMENT, - LOGSERVER_VERSION, - LOGSERVER_HOST, - LOGSERVER_BASEURL, - LOGSERVER_API_KEY, +const { + NODE_ENV, + LOGSERVER_APPLICATION, + LOGSERVER_SERVICE, + LOGSERVER_ENVIRONMENT, + LOGSERVER_VERSION, + LOGSERVER_HOST, + LOGSERVER_BASEURL, + LOGSERVER_API_KEY, } = process.env; // this writes to STDOUT -let consoleTransport = { - target: "pino-pretty", - options: { - singleLine: true, // to prevent cramming up console - //add or remove what you don't want to log accordingly - ignore: - "pid,hostname,request.id,request.headers,response.headers", - }, +const consoleTransport = { + target: "pino-pretty", + options: { + singleLine: true, // to prevent cramming up console + //add or remove what you don't want to log accordingly + ignore: "pid,hostname,request.id,request.headers,response.headers", + }, }; // this sends to Logging Server (Not used in dev) -let logServerTransport = { - target: "@codebucket/logserver-transport", - options: { - // application related for tagging - application: LOGSERVER_APPLICATION, //Name of this application - service: LOGSERVER_SERVICE, //Service (Docker, Pm2 etc) - environment: LOGSERVER_ENVIRONMENT, //Environment - version: LOGSERVER_VERSION, //Version Of This application - host: LOGSERVER_HOST, //Hostname where this application is running +const logServerTransport = { + target: "@codebucket/logserver-transport", + options: { + // application related for tagging + application: LOGSERVER_APPLICATION, //Name of this application + service: LOGSERVER_SERVICE, //Service (Docker, Pm2 etc) + environment: LOGSERVER_ENVIRONMENT, //Environment + version: LOGSERVER_VERSION, //Version Of This application + host: LOGSERVER_HOST, //Hostname where this application is running - //logging server related - apiBaseUrl: LOGSERVER_BASEURL, //BaseUrl of logging server - apiKey: LOGSERVER_API_KEY, //Api Key of logging server - //apiLogEndpoint: //default:log + //logging server related + apiBaseUrl: LOGSERVER_BASEURL, //BaseUrl of logging server + apiKey: LOGSERVER_API_KEY, //Api Key of logging server + //apiLogEndpoint: //default:log - //transport related (We send logs to server in batches) - //batchInterval: default 5000ms - //batchCount: default 20 - //logs will be sent when interval is crossed or count is reached - }, + //transport related (We send logs to server in batches) + //batchInterval: default 5000ms + //batchCount: default 20 + //logs will be sent when interval is crossed or count is reached + }, }; let targets = [consoleTransport]; -if (NODE_ENV == "STAGE" || NODE_ENV == "stage") { - targets = [consoleTransport, logServerTransport]; -} else if (NODE_ENV == "PRODUCTION" || NODE_ENV == "production") { - targets = [logServerTransport]; +if (NODE_ENV === "STAGE" || NODE_ENV === "stage") { + targets = [consoleTransport, logServerTransport]; +} else if (NODE_ENV === "PRODUCTION" || NODE_ENV === "production") { + targets = [logServerTransport]; } const transports = pino.transport({ - targets, + targets, }); const logger = pino( - { - redact: { - //provide paths to prevent logging sensitive information - paths: ["*.password", "*.headers.token", "*.headers.authorization"], - censor: "[REDACTED]", - }, - }, - transports + { + redact: { + //provide paths to prevent logging sensitive information + paths: ["*.password", "*.headers.token", "*.headers.authorization"], + censor: "[REDACTED]", + }, + }, + transports, ); module.exports = logger; diff --git a/utils/mail.js b/utils/mail.js index 9603d11..9641ed9 100644 --- a/utils/mail.js +++ b/utils/mail.js @@ -11,24 +11,29 @@ const transporter = nodemailer.createTransport({ }); transporter.verify(error => { - if (error) console.error(error); - else console.log(`Success`); + if (error) { + console.error(error); + } else { + console.log(`Success`); + } }); module.exports = { sendMail: async (recipient, subject, body, attachments = []) => { try { - let options = { + const options = { from: `"Govt. Of Bihar" ${process.env.EMAIL_USER}`, // sender address to: recipient, // list of receivers priority: "high", - subject: subject, + subject, html: body, attachments, }; transporter.sendMail(options, (error, info) => { - if (error) console.error(error); + if (error) { + console.error(error); + } console.log(info?.messageId); }); diff --git a/utils/message-helper.js b/utils/message-helper.js index 6b48965..8e00b50 100644 --- a/utils/message-helper.js +++ b/utils/message-helper.js @@ -1,30 +1,30 @@ const crypto = require("crypto"); module.exports = { - encryptedPassword: (password) => { - try { - const shasum = crypto.createHash("sha1"); - const data = shasum.update(password); + encryptedPassword: password => { + try { + const shasum = crypto.createHash("sha1"); + const data = shasum.update(password); - const enc = data.digest("hex"); + const enc = data.digest("hex"); - return enc; - } catch (error) { - console.error(error); - return "0"; - } - }, - hashGenerator: async (USERNAME, SENDERID, messgae, KEY) => { - try { - const hash = crypto.createHash("sha512"); - const data = hash.update(`${USERNAME}${SENDERID}${messgae}${KEY}`); - const gen_hash = data.digest("hex"); - console.log("hash : " + gen_hash); + return enc; + } catch (error) { + console.error(error); + return "0"; + } + }, + hashGenerator: async (USERNAME, SENDERID, messgae, KEY) => { + try { + const hash = crypto.createHash("sha512"); + const data = hash.update(`${USERNAME}${SENDERID}${messgae}${KEY}`); + const gen_hash = data.digest("hex"); + console.log(`hash : ${gen_hash}`); - return gen_hash; - } catch (error) { - console.error(error); - return 0; - } - }, + return gen_hash; + } catch (error) { + console.error(error); + return 0; + } + }, }; diff --git a/utils/message.js b/utils/message.js index 661ce0d..dff3fa8 100644 --- a/utils/message.js +++ b/utils/message.js @@ -1,53 +1,45 @@ const axios = require("axios"); -const http = require("http"); - -const { PASSWORDSMS, ENDPOINT, KEY, SENDERID, USERNAMESMS, AUTHKEY } = - process.env; +const { PASSWORDSMS, ENDPOINT, KEY, SENDERID, USERNAMESMS } = process.env; const { encryptedPassword, hashGenerator } = require("./message-helper"); module.exports = { - messenger: async (message, phone, DLT) => { - try { - const encPassword = encryptedPassword(PASSWORDSMS), - templateId = DLT; + messenger: async (message, phone, DLT) => { + try { + const encPassword = encryptedPassword(PASSWORDSMS), + templateId = DLT; - let finalMessage = message.trim(); + const finalMessage = message.trim(); - const hash = await hashGenerator( - USERNAMESMS, - SENDERID, - finalMessage, - KEY - ); + const hash = await hashGenerator(USERNAMESMS, SENDERID, finalMessage, KEY); - const query = `username=${USERNAMESMS}&password=${encPassword}&smsservicetype=otpmsg&content=${finalMessage}&mobileno=${phone}&senderid=${SENDERID}&key=${hash}&templateid=${templateId}`; + const query = `username=${USERNAMESMS}&password=${encPassword}&smsservicetype=otpmsg&content=${finalMessage}&mobileno=${phone}&senderid=${SENDERID}&key=${hash}&templateid=${templateId}`; - axios - .post(ENDPOINT, query) - .then(async (resp) => { - console.log(resp.data); - }) - .catch(function (error) { - console.error(error); - throw error; - }); - } catch (error) { - console.log(error); - return 0; - } - }, - generateOtp: (lenght = 4) => { - try { - const string = "123456789"; - let OTP = ""; - const len = string.length; - for (let i = 0; i < lenght; i++) { - OTP += string[Math.floor(Math.random() * len)]; - } - return OTP; - } catch (error) { - console.log(error); - throw error; - } - }, + axios + .post(ENDPOINT, query) + .then(async resp => { + console.log(resp.data); + }) + .catch(error => { + console.error(error); + throw error; + }); + } catch (error) { + console.log(error); + return 0; + } + }, + generateOtp: (lenght = 4) => { + try { + const string = "123456789"; + let OTP = ""; + const len = string.length; + for (let i = 0; i < lenght; i++) { + OTP += string[Math.floor(Math.random() * len)]; + } + return OTP; + } catch (error) { + console.log(error); + throw error; + } + }, }; diff --git a/utils/notifications.js b/utils/notifications.js deleted file mode 100644 index 2e6bfe1..0000000 --- a/utils/notifications.js +++ /dev/null @@ -1,36 +0,0 @@ -const sequelize = require("../../config/database"); - -const gcm = require("node-gcm"); -const { getDate } = require("./time"); -const Sequelize = require("sequelize"); - -module.exports = { - notification: async function (body, subject) { - try { - const sender = new gcm.Sender(process.env.GCMSENDER); - - const message = new gcm.Message({ - notification: { - title: subject, - body: body, - }, - }); - - sender.send( - message, - { - registrationTokens: fcm, - }, - async function (error, response) { - if (error) { - console.log(error); - } else { - console.log(response); - } - } - ); - } catch (error) { - console.log(error); - } - }, -}; diff --git a/utils/search-util.js b/utils/search-util.js index bbd10ab..70dd92d 100644 --- a/utils/search-util.js +++ b/utils/search-util.js @@ -1,45 +1,49 @@ const { LINK, TEXT } = require("./constant"); const getSearchAbleData = ({ data: { uri, link_title }, children }) => { - let mData = []; - mData = [...mData, uri, ...(link_title ? [link_title] : [])]; - if (!children) return mData; + let mData = []; + mData = [...mData, uri, ...(link_title ? [link_title] : [])]; + if (!children) { + return mData; + } - children.map((v) => { - mData = [...mData, ...getSearchAbleData(v)]; - }); + children.map(v => { + mData = [...mData, ...getSearchAbleData(v)]; + }); - return mData; + return mData; }; const checkForMatch = (a, b) => { - let c = 0; - a.map((v) => { - let d = 0; - b.map((v1) => { - if (v1.toLowerCase().includes(v.toLowerCase())) d++; - }); - if (d > 0) { - c++; - } - }); + let c = 0; + a.map(v => { + let d = 0; + b.map(v1 => { + if (v1.toLowerCase().includes(v.toLowerCase())) { + d++; + } + }); + if (d > 0) { + c++; + } + }); - return c >= a.length; + return c >= a.length; }; -const getSearchType = (type) => { - switch (type) { - case 0: - return `AND type = '${LINK}'`; - case 1: - return ""; - case 2: - return `AND type = '${TEXT}'`; - } +const getSearchType = type => { + switch (type) { + case 0: + return `AND type = '${LINK}'`; + case 1: + return ""; + case 2: + return `AND type = '${TEXT}'`; + } }; module.exports = { - getSearchAbleData, - checkForMatch, - getSearchType, + getSearchAbleData, + checkForMatch, + getSearchType, }; diff --git a/utils/time.js b/utils/time.js index 3efe96c..2721c0c 100644 --- a/utils/time.js +++ b/utils/time.js @@ -11,7 +11,7 @@ function secondsToHMS(secs) { } const sign = secs < 0 ? "-" : ""; secs = Math.abs(secs); - return sign + z((secs / 3600) | 0) + ":" + z(((secs % 3600) / 60) | 0); + return `${sign + z((secs / 3600) | 0)}:${z(((secs % 3600) / 60) | 0)}`; } module.exports = { @@ -25,40 +25,40 @@ module.exports = { return toSeconds(time); }, toDaysHourMin: p => { - let d = Math.floor(p / (3600 * 24)); + const d = Math.floor(p / (3600 * 24)); p -= d * 3600 * 24; - let h = Math.floor(p / 3600); + const h = Math.floor(p / 3600); p -= h * 3600; - let m = Math.floor(p / 60); + const m = Math.floor(p / 60); - let tmp = []; + const tmp = []; - d && tmp.push(d + "d"); + d && tmp.push(`${d}d`); - (d || h) && tmp.push(h + "h"); + (d || h) && tmp.push(`${h}h`); - (d || h || m) && tmp.push(m + "m"); + (d || h || m) && tmp.push(`${m}m`); - let datetime = tmp.join(" "); + const datetime = tmp.join(" "); return datetime; }, dateSort: date => { // Format YYYY-MM-DD - date.sort(function (a, b) { - let aa = a.split("-").join(), + date.sort((a, b) => { + const aa = a.split("-").join(), bb = b.split("-").join(); if (aa < bb) { - return -1; - } else if (aa > bb) { - return 1; - } else { - return 0; - } + return -1; + } else if (aa > bb) { + return 1; + } else { + return 0; + } }); return { @@ -82,8 +82,8 @@ module.exports = { return parseInt(moment.utc(date).utcOffset("+05:30").format("e"), 10); }, dateDiff: (newDate, pastDate, format = "seconds") => { - let date1 = moment(newDate); - let date2 = moment(pastDate); + const date1 = moment(newDate); + const date2 = moment(pastDate); return date2.diff(date1, format); }, ISO: (date, format) => { @@ -91,7 +91,7 @@ module.exports = { }, getDates: (startDate, endDate, steps = 3) => { const dateArray = []; - let currentDate = new Date(startDate); + const currentDate = new Date(startDate); while (currentDate <= new Date(endDate)) { dateArray.push(moment(new Date(currentDate)).format("YYYY-MM-DD")); @@ -103,7 +103,7 @@ module.exports = { }, financialYear: date => { let fiscalYear = ""; - let today = date ? new Date(date) : new Date(); + const today = date ? new Date(date) : new Date(); if (today.getMonth() + 1 <= 3) { fiscalYear = today.getFullYear() - 1; } else { diff --git a/utils/token.js b/utils/token.js index 42a4690..1654fac 100644 --- a/utils/token.js +++ b/utils/token.js @@ -4,5 +4,5 @@ const users = require("../helper/users"); const { USER } = users; module.exports = function (id, userType = USER) { - return jwt.sign({ userId: id, userType }, process.env.JWT_PRIVATE_KEY); + return jwt.sign({ userId: id, userType }, process.env.JWT_PRIVATE_KEY); }; diff --git a/utils/upload.js b/utils/upload.js index b02b7f5..1eb9d25 100644 --- a/utils/upload.js +++ b/utils/upload.js @@ -4,67 +4,68 @@ const formidable = require("formidable"); const copyFilePromise = util.promisify(fs.copyFile); const NodeClam = require("clamscan"); -let scanFile = async (filePath) => { - if (process.env.VIRUS_CHECKER == "OFF") return true; - const clamscan = await new NodeClam().init({ - remove_infected: true, - debug_mode: false, - scan_recursively: false, - clamdscan: { - socket: process.env.CLAMDSCAN_SOCKET || "/var/run/clamav/clamd.ctl", - timeout: 120000, - local_fallback: true, - path: process.env.CLAMDSCAN_PATH || "/var/lib/clamav", - config_file: - process.env.CLAMDSCAN_CONFIG_FILE || "/etc/clamav/clamd.conf", - }, - }); +const scanFile = async filePath => { + if (process.env.VIRUS_CHECKER === "OFF") { + return true; + } + const clamscan = await new NodeClam().init({ + remove_infected: true, + debug_mode: false, + scan_recursively: false, + clamdscan: { + socket: process.env.CLAMDSCAN_SOCKET || "/var/run/clamav/clamd.ctl", + timeout: 120000, + local_fallback: true, + path: process.env.CLAMDSCAN_PATH || "/var/lib/clamav", + config_file: process.env.CLAMDSCAN_CONFIG_FILE || "/etc/clamav/clamd.conf", + }, + }); - const { is_infected, viruses } = await clamscan.scan_file(filePath); + const { is_infected, viruses } = await clamscan.scan_file(filePath); - if (is_infected) { - console.error(`Virus scan failed, file INFECTED`, { filePath, viruses }); - } else { - console.log(`Virus scan OK`, { filePath }); - } + if (is_infected) { + console.error(`Virus scan failed, file INFECTED`, { filePath, viruses }); + } else { + console.log(`Virus scan OK`, { filePath }); + } - return is_infected; + return is_infected; }; const copyFiles = (srcDir, destDir, dir) => { - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - return copyFilePromise(srcDir, destDir); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + return copyFilePromise(srcDir, destDir); }; -const formidableUpload = async (req) => { - try { - const form = new formidable.IncomingForm(); - console.log(form.parse); - form.keepExtensions = true; - form.on("error", (e) => console.log(e)); - form.on("aborted", () => console.log("aborted")); - form.multiples = true; - const formfields = await new Promise(function (resolve, reject) { - form.parse(req, function (err, fields, files) { - if (err) { - reject(new Error("Form Not parsed ")); - return; - } +const formidableUpload = async req => { + try { + const form = new formidable.IncomingForm(); + console.log(form.parse); + form.keepExtensions = true; + form.on("error", e => console.log(e)); + form.on("aborted", () => console.log("aborted")); + form.multiples = true; + const formfields = await new Promise((resolve, reject) => { + form.parse(req, (err, fields, files) => { + if (err) { + reject(new Error("Form Not parsed ")); + return; + } - resolve({ fields, files }); - }); // form.parse - }); + resolve({ fields, files }); + }); // form.parse + }); - return formfields; - } catch (error) { - console.error("Error in formidable upload:", error.message); - } + return formfields; + } catch (error) { + console.error("Error in formidable upload:", error.message); + } }; module.exports = { - formidableUpload, - scanFile, - copyFiles, + formidableUpload, + scanFile, + copyFiles, }; From 0f38dcec7bd571212a632befebc804589b3f243f Mon Sep 17 00:00:00 2001 From: DaraSingh1998 Date: Sat, 22 Nov 2025 22:14:07 +0530 Subject: [PATCH 3/4] Updated eslint --- .husky/pre-commit | 3 --- docs/code-quality.md | 9 +++++---- package.json | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index d24fdfc..2312dc5 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - npx lint-staged diff --git a/docs/code-quality.md b/docs/code-quality.md index d1e34eb..8396a5d 100644 --- a/docs/code-quality.md +++ b/docs/code-quality.md @@ -147,9 +147,10 @@ Git hooks automatically run linting and formatting before each commit. ### What Happens on Commit: 1. **lint-staged** runs on staged files -2. **ESLint** fixes issues in `.js` files -3. **Prettier** formats all staged files -4. If errors can't be auto-fixed, commit is blocked +2. **Prettier** formats all staged files (and auto-fixes formatting) +3. **ESLint** checks for code quality issues +4. If **ANY** linting error is found, the commit is **blocked** and errors are displayed +5. You must fix the errors manually and try committing again ### Configuration @@ -164,7 +165,7 @@ npx lint-staged ```json { "lint-staged": { - "*.js": ["eslint --fix", "prettier --write"], + "*.js": ["eslint", "prettier --write"], "*.{json,md,yml,yaml}": ["prettier --write"] } } diff --git a/package.json b/package.json index bade7c5..eebf928 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ }, "lint-staged": { "*.js": [ - "eslint --fix", + "eslint", "prettier --write" ], "*.{json,md,yml,yaml}": [ From f93507764c4a8611bbbf749cc75d42a24f1d1015 Mon Sep 17 00:00:00 2001 From: DaraSingh1998 Date: Sat, 22 Nov 2025 22:14:48 +0530 Subject: [PATCH 4/4] Updated eslint --- .env.development => env.development.example | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .env.development => env.development.example (100%) diff --git a/.env.development b/env.development.example similarity index 100% rename from .env.development rename to env.development.example