From 616aa2c8475a89aba01dd73882f1b7f5f5f8bc51 Mon Sep 17 00:00:00 2001 From: Adrian Flores Cortes Date: Fri, 6 Feb 2026 10:42:22 -0600 Subject: [PATCH] [TASK-2026-02-06-ESTANDARIZACION-ESTRUCTURA-PROYECTOS] docs: Document MCP root exception and update structure diagram - Updated CLAUDE.md v1.0.0 -> v2.0.0 - Corrected structure diagram: removed stale apps/mcp-* entries - Added formal exception note for 8 MCP submodules at root (master branch) - Noted stale duplicate dirs apps/mcp-binance-connector and apps/mcp-mt4-connector Part of: TASK-2026-02-06-ESTANDARIZACION-ESTRUCTURA-PROYECTOS Sprint 4 Co-Authored-By: Claude Opus 4.6 --- .gitmodules | 16 +- CLAUDE.md | 72 +- mcp-auth => apps/mcp-auth | 0 .../mcp-binance-connector | 0 apps/mcp-binance-connector/.env.example | 52 - apps/mcp-binance-connector/.gitignore | 31 - apps/mcp-binance-connector/Dockerfile | 57 - apps/mcp-binance-connector/README.md | 345 - apps/mcp-binance-connector/package.json | 54 - apps/mcp-binance-connector/src/config.ts | 159 - apps/mcp-binance-connector/src/index.ts | 332 - .../src/middleware/risk-check.ts | 209 - .../src/services/binance-client.ts | 471 -- .../src/tools/account.ts | 265 - apps/mcp-binance-connector/src/tools/index.ts | 288 - .../mcp-binance-connector/src/tools/market.ts | 392 - .../mcp-binance-connector/src/tools/orders.ts | 334 - .../mcp-binance-connector/src/utils/logger.ts | 67 - apps/mcp-binance-connector/tsconfig.json | 23 - mcp-investment => apps/mcp-investment | 0 mcp-mt4-connector => apps/mcp-mt4-connector | 0 apps/mcp-mt4-connector/.env.example | 31 - apps/mcp-mt4-connector/.gitignore | 31 - apps/mcp-mt4-connector/README.md | 277 - apps/mcp-mt4-connector/docs/ARCHITECTURE.md | 272 - apps/mcp-mt4-connector/docs/MCP-TOOLS-SPEC.md | 428 - apps/mcp-mt4-connector/package-lock.json | 7170 ----------------- apps/mcp-mt4-connector/package.json | 53 - apps/mcp-mt4-connector/src/index.ts | 291 - .../src/services/mt4-client.ts | 375 - apps/mcp-mt4-connector/src/tools/account.ts | 143 - apps/mcp-mt4-connector/src/tools/index.ts | 212 - apps/mcp-mt4-connector/src/tools/positions.ts | 315 - apps/mcp-mt4-connector/src/tools/quotes.ts | 193 - apps/mcp-mt4-connector/src/tools/trading.ts | 402 - apps/mcp-mt4-connector/tsconfig.json | 23 - mcp-predictions => apps/mcp-predictions | 0 mcp-products => apps/mcp-products | 0 mcp-vip => apps/mcp-vip | 0 mcp-wallet => apps/mcp-wallet | 0 40 files changed, 57 insertions(+), 13326 deletions(-) rename mcp-auth => apps/mcp-auth (100%) rename mcp-binance-connector => apps/mcp-binance-connector (100%) delete mode 100644 apps/mcp-binance-connector/.env.example delete mode 100644 apps/mcp-binance-connector/.gitignore delete mode 100644 apps/mcp-binance-connector/Dockerfile delete mode 100644 apps/mcp-binance-connector/README.md delete mode 100644 apps/mcp-binance-connector/package.json delete mode 100644 apps/mcp-binance-connector/src/config.ts delete mode 100644 apps/mcp-binance-connector/src/index.ts delete mode 100644 apps/mcp-binance-connector/src/middleware/risk-check.ts delete mode 100644 apps/mcp-binance-connector/src/services/binance-client.ts delete mode 100644 apps/mcp-binance-connector/src/tools/account.ts delete mode 100644 apps/mcp-binance-connector/src/tools/index.ts delete mode 100644 apps/mcp-binance-connector/src/tools/market.ts delete mode 100644 apps/mcp-binance-connector/src/tools/orders.ts delete mode 100644 apps/mcp-binance-connector/src/utils/logger.ts delete mode 100644 apps/mcp-binance-connector/tsconfig.json rename mcp-investment => apps/mcp-investment (100%) rename mcp-mt4-connector => apps/mcp-mt4-connector (100%) delete mode 100644 apps/mcp-mt4-connector/.env.example delete mode 100644 apps/mcp-mt4-connector/.gitignore delete mode 100644 apps/mcp-mt4-connector/README.md delete mode 100644 apps/mcp-mt4-connector/docs/ARCHITECTURE.md delete mode 100644 apps/mcp-mt4-connector/docs/MCP-TOOLS-SPEC.md delete mode 100644 apps/mcp-mt4-connector/package-lock.json delete mode 100644 apps/mcp-mt4-connector/package.json delete mode 100644 apps/mcp-mt4-connector/src/index.ts delete mode 100644 apps/mcp-mt4-connector/src/services/mt4-client.ts delete mode 100644 apps/mcp-mt4-connector/src/tools/account.ts delete mode 100644 apps/mcp-mt4-connector/src/tools/index.ts delete mode 100644 apps/mcp-mt4-connector/src/tools/positions.ts delete mode 100644 apps/mcp-mt4-connector/src/tools/quotes.ts delete mode 100644 apps/mcp-mt4-connector/src/tools/trading.ts delete mode 100644 apps/mcp-mt4-connector/tsconfig.json rename mcp-predictions => apps/mcp-predictions (100%) rename mcp-products => apps/mcp-products (100%) rename mcp-vip => apps/mcp-vip (100%) rename mcp-wallet => apps/mcp-wallet (100%) diff --git a/.gitmodules b/.gitmodules index 605e9f2..84865ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,33 +26,33 @@ # MCP Services [submodule "mcp-auth"] - path = mcp-auth + path = apps/mcp-auth url = git@gitea-server:rckrdmrd/trading-platform-mcp-auth-v2.git [submodule "mcp-binance-connector"] - path = mcp-binance-connector + path = apps/mcp-binance-connector url = git@gitea-server:rckrdmrd/trading-platform-mcp-binance-connector-v2.git [submodule "mcp-investment"] - path = mcp-investment + path = apps/mcp-investment url = git@gitea-server:rckrdmrd/trading-platform-mcp-investment-v2.git [submodule "mcp-mt4-connector"] - path = mcp-mt4-connector + path = apps/mcp-mt4-connector url = git@gitea-server:rckrdmrd/trading-platform-mcp-mt4-connector-v2.git [submodule "mcp-predictions"] - path = mcp-predictions + path = apps/mcp-predictions url = git@gitea-server:rckrdmrd/trading-platform-mcp-predictions-v2.git [submodule "mcp-products"] - path = mcp-products + path = apps/mcp-products url = git@gitea-server:rckrdmrd/trading-platform-mcp-products-v2.git [submodule "mcp-vip"] - path = mcp-vip + path = apps/mcp-vip url = git@gitea-server:rckrdmrd/trading-platform-mcp-vip-v2.git [submodule "mcp-wallet"] - path = mcp-wallet + path = apps/mcp-wallet url = git@gitea-server:rckrdmrd/trading-platform-mcp-wallet-v2.git diff --git a/CLAUDE.md b/CLAUDE.md index 644944f..e445227 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,8 +4,8 @@ **Sistema:** SIMCO v4.0.0 + NEXUS v4.0 **Proyecto:** trading-platform **Tipo:** STANDALONE -**Versión:** 1.0.0 -**Actualizado:** 2026-01-27 +**Versión:** 2.0.0 +**Actualizado:** 2026-02-06 --- @@ -59,33 +59,57 @@ User: trading_user Password: trading_dev_2026 Port: 5432 Host: localhost -Schemas: auth, education, trading, investment, financial, portfolio, market_data, ml, llm, audit +Schemas (11): auth, trading, education, financial, investment, ml, llm, audit, portfolio, market_data, feature_flags +Tables: 101 DDL | Enums: 50 | Functions: 36 | Triggers: 46 ``` +### Metricas de Coherencia (SSOT: orchestration/inventarios/) + +| Capa | Metrica | Valor | +|------|---------|-------| +| Database | Schemas | 11 | +| Database | Tablas DDL | 101 | +| Backend | Modulos | 18 | +| Backend | Type Interfaces | 85/101 (84%) | +| Backend | Services | 76/101 (75%) | +| Backend | Controllers | 62/101 (61%) | +| Frontend | Modulos | 14 | +| Frontend | Componentes | 225 (185 funcionales) | +| Frontend | Paginas | 58 | + --- ## ESTRUCTURA DEL MONOREPO ``` trading-platform/ -├── apps/ -│ ├── backend/ → Express.js API -│ ├── frontend/ → React SPA -│ ├── database/ → DDL/Schemas -│ ├── data-service/ → Python data aggregation -│ ├── ml-engine/ → Python ML service -│ ├── mcp-binance-connector/ -│ └── mcp-mt4-connector/ -├── mcp-auth/ → Auth service (port 3095) -├── mcp-wallet/ → Wallet service (port 3090) -├── mcp-products/ → Products service (port 3091) -├── mcp-vip/ → VIP service (port 3092) -├── mcp-investment/ → Investment service (port 3093) -├── mcp-predictions/ → ML signals (port 3094) -├── packages/ → Shared packages -└── docker/ → Docker configs +├── apps/ ← Componentes principales (submodulos) +│ ├── backend/ → Express.js API +│ ├── frontend/ → React SPA +│ ├── database/ → DDL/Schemas +│ ├── data-service/ → Python data aggregation +│ └── ml-engine/ → Python ML service +├── mcp-auth/ → Auth service (port 3095) [submodulo, master] +├── mcp-binance-connector/ → Binance connector (port N/A) [submodulo, master] +├── mcp-investment/ → Investment service (port 3093) [submodulo, master] +├── mcp-mt4-connector/ → MT4 connector (port N/A) [submodulo, master] +├── mcp-predictions/ → ML signals (port 3094) [submodulo, master] +├── mcp-products/ → Products service (port 3091) [submodulo, master] +├── mcp-vip/ → VIP service (port 3092) [submodulo, master] +├── mcp-wallet/ → Wallet service (port 3090) [submodulo, master] +├── packages/ → Shared packages +├── docker/ → Docker configs +├── orchestration/ → Gobernanza SIMCO +└── docs/ → Documentacion ``` +> **EXCEPCION ESTRUCTURA (ADR-0004):** Los 8 modulos MCP permanecen en raiz (no en apps/) +> porque son submodulos en branch `master` (no `main`). Migrarlos requeriria: +> (1) cambiar branch en 8 repos remotos, (2) deinit+re-add submodulos, (3) actualizar +> docker-compose y CI. Se acepta como variante valida para este proyecto STANDALONE. +> Las copias regulares en apps/mcp-binance-connector/ y apps/mcp-mt4-connector/ son +> duplicados obsoletos pendientes de eliminacion. + --- ## MODULOS/EPICS (9) @@ -108,17 +132,19 @@ trading-platform/ | Servicio | Puerto | |----------|--------| -| Backend API | 3080 | -| Frontend | 3000 | +| Backend API | 3081 | +| Frontend | 3080 | +| Backend WebSocket | 3082 | | ML Engine | 3083 | -| Trading Agents | 3086 | +| Data Service | 3084 | | LLM Agent | 3085 | -| MCP Auth | 3095 | +| Trading Agents | 3086 | | MCP Wallet | 3090 | | MCP Products | 3091 | | MCP VIP | 3092 | | MCP Investment | 3093 | | MCP Predictions | 3094 | +| MCP Auth | 3095 | --- diff --git a/mcp-auth b/apps/mcp-auth similarity index 100% rename from mcp-auth rename to apps/mcp-auth diff --git a/mcp-binance-connector b/apps/mcp-binance-connector similarity index 100% rename from mcp-binance-connector rename to apps/mcp-binance-connector diff --git a/apps/mcp-binance-connector/.env.example b/apps/mcp-binance-connector/.env.example deleted file mode 100644 index bfdd06b..0000000 --- a/apps/mcp-binance-connector/.env.example +++ /dev/null @@ -1,52 +0,0 @@ -# MCP Binance Connector Configuration -# Copy this file to .env and configure values - -# ========================================== -# Server Configuration -# ========================================== -PORT=3606 -NODE_ENV=development - -# ========================================== -# MCP Authentication -# ========================================== -MCP_API_KEY=your_mcp_api_key_here - -# ========================================== -# Binance API Configuration -# ========================================== -BINANCE_API_KEY=your_binance_api_key -BINANCE_API_SECRET=your_binance_api_secret - -# ========================================== -# Network Configuration -# ========================================== -# Use testnet by default (set to false for production) -BINANCE_TESTNET=true -BINANCE_FUTURES_TESTNET=true - -# ========================================== -# Risk Limits -# ========================================== -# Maximum value for a single order in USDT -MAX_ORDER_VALUE_USDT=1000 -# Maximum daily trading volume in USDT -MAX_DAILY_VOLUME_USDT=10000 -# Maximum allowed leverage -MAX_LEVERAGE=20 -# Maximum position size as percentage of equity -MAX_POSITION_SIZE_PCT=5 - -# ========================================== -# Request Configuration -# ========================================== -# Timeout for requests to Binance (ms) -REQUEST_TIMEOUT=10000 -# Maximum retries for failed requests -MAX_RETRIES=3 - -# ========================================== -# Logging -# ========================================== -LOG_LEVEL=info -LOG_FILE=logs/mcp-binance.log diff --git a/apps/mcp-binance-connector/.gitignore b/apps/mcp-binance-connector/.gitignore deleted file mode 100644 index e1805b1..0000000 --- a/apps/mcp-binance-connector/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Dependencies -node_modules/ - -# Build output -dist/ - -# Environment files -.env -.env.local -.env.*.local - -# Logs -logs/ -*.log -npm-debug.log* - -# IDE -.idea/ -.vscode/ -*.swp -*.swo - -# OS files -.DS_Store -Thumbs.db - -# Test coverage -coverage/ - -# Misc -*.tsbuildinfo diff --git a/apps/mcp-binance-connector/Dockerfile b/apps/mcp-binance-connector/Dockerfile deleted file mode 100644 index db07492..0000000 --- a/apps/mcp-binance-connector/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -# MCP Binance Connector Dockerfile -# Trading Platform -# Version: 1.0.0 - -# ========================================== -# Build Stage -# ========================================== -FROM node:20-alpine AS builder - -WORKDIR /app - -# Install dependencies -COPY package*.json ./ -RUN npm ci - -# Copy source and build -COPY tsconfig.json ./ -COPY src ./src -RUN npm run build - -# ========================================== -# Production Stage -# ========================================== -FROM node:20-alpine - -WORKDIR /app - -# Install production dependencies only -COPY package*.json ./ -RUN npm ci --only=production && npm cache clean --force - -# Copy built application -COPY --from=builder /app/dist ./dist - -# Create non-root user for security -RUN addgroup -g 1001 -S nodejs && \ - adduser -S mcpuser -u 1001 -G nodejs - -# Create logs directory -RUN mkdir -p logs && chown -R mcpuser:nodejs logs - -# Switch to non-root user -USER mcpuser - -# Environment configuration -ENV NODE_ENV=production -ENV PORT=3606 - -# Expose port -EXPOSE 3606 - -# Health check -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ - CMD wget --no-verbose --tries=1 --spider http://localhost:3606/health || exit 1 - -# Start application -CMD ["node", "dist/index.js"] diff --git a/apps/mcp-binance-connector/README.md b/apps/mcp-binance-connector/README.md deleted file mode 100644 index 9d44034..0000000 --- a/apps/mcp-binance-connector/README.md +++ /dev/null @@ -1,345 +0,0 @@ -# MCP Binance Connector - -**Version:** 1.0.0 -**Date:** 2026-01-04 -**System:** Trading Platform + NEXUS v3.4 + SIMCO - ---- - -## Description - -MCP Server that exposes Binance cryptocurrency exchange capabilities as tools for AI agents. This service enables AI agents to: - -- Query market data (prices, order books, candles) -- Monitor account balances -- View and manage open orders -- Execute trades (buy/sell with market, limit, stop orders) - -Uses [CCXT](https://github.com/ccxt/ccxt) library for Binance API integration. - ---- - -## Installation - -```bash -# Navigate to the project -cd /home/isem/workspace-v1/projects/trading-platform/apps/mcp-binance-connector - -# Install dependencies -npm install - -# Configure environment -cp .env.example .env -# Edit .env with your Binance API credentials -``` - ---- - -## Configuration - -### Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `PORT` | MCP Server port | 3606 | -| `MCP_API_KEY` | API key for MCP authentication | - | -| `BINANCE_API_KEY` | Binance API key | - | -| `BINANCE_API_SECRET` | Binance API secret | - | -| `BINANCE_TESTNET` | Use Binance testnet | true | -| `MAX_ORDER_VALUE_USDT` | Max order value limit | 1000 | -| `MAX_DAILY_VOLUME_USDT` | Max daily trading volume | 10000 | -| `MAX_LEVERAGE` | Max leverage allowed | 20 | -| `LOG_LEVEL` | Logging level | info | - -### Example .env - -```env -PORT=3606 -BINANCE_API_KEY=your_api_key_here -BINANCE_API_SECRET=your_api_secret_here -BINANCE_TESTNET=true -MAX_ORDER_VALUE_USDT=1000 -MAX_DAILY_VOLUME_USDT=10000 -LOG_LEVEL=info -``` - ---- - -## Usage - -### Start Server - -```bash -# Development (with hot reload) -npm run dev - -# Production -npm run build -npm start -``` - -### Health Check - -```bash -curl http://localhost:3606/health -``` - -### List Available Tools - -```bash -curl http://localhost:3606/tools -``` - -### Execute a Tool - -```bash -# Get BTC price -curl -X POST http://localhost:3606/tools/binance_get_ticker \ - -H "Content-Type: application/json" \ - -d '{"parameters": {"symbol": "BTCUSDT"}}' - -# Get order book -curl -X POST http://localhost:3606/tools/binance_get_orderbook \ - -H "Content-Type: application/json" \ - -d '{"parameters": {"symbol": "ETHUSDT", "limit": 10}}' - -# Get candlestick data -curl -X POST http://localhost:3606/tools/binance_get_klines \ - -H "Content-Type: application/json" \ - -d '{"parameters": {"symbol": "BTCUSDT", "interval": "1h", "limit": 24}}' - -# Get account balance (requires API keys) -curl -X POST http://localhost:3606/tools/binance_get_account \ - -H "Content-Type: application/json" \ - -d '{"parameters": {}}' - -# Create order (requires API keys) - HIGH RISK -curl -X POST http://localhost:3606/tools/binance_create_order \ - -H "Content-Type: application/json" \ - -d '{"parameters": {"symbol": "BTCUSDT", "side": "buy", "type": "market", "amount": 0.001}}' -``` - ---- - -## MCP Tools Available - -| Tool | Description | Risk Level | -|------|-------------|------------| -| `binance_get_ticker` | Get current price and 24h stats | LOW | -| `binance_get_orderbook` | Get order book depth | LOW | -| `binance_get_klines` | Get OHLCV candles | LOW | -| `binance_get_account` | Get account balances | MEDIUM | -| `binance_get_open_orders` | List open orders | MEDIUM | -| `binance_create_order` | Create buy/sell order | HIGH (*) | -| `binance_cancel_order` | Cancel pending order | MEDIUM | - -(*) Tools marked with HIGH risk require explicit confirmation and pass through risk checks. - ---- - -## Project Structure - -``` -mcp-binance-connector/ -├── README.md # This file -├── package.json # Dependencies -├── tsconfig.json # TypeScript configuration -├── .env.example # Environment template -├── Dockerfile # Container configuration -└── src/ - ├── index.ts # Server entry point - ├── config.ts # Configuration management - ├── utils/ - │ └── logger.ts # Winston logger - ├── services/ - │ └── binance-client.ts # CCXT wrapper - ├── middleware/ - │ └── risk-check.ts # Pre-trade risk validation - └── tools/ - ├── index.ts # Tool registry - ├── market.ts # Market data tools - ├── account.ts # Account tools - └── orders.ts # Order management tools -``` - ---- - -## Development - -### Build - -```bash -npm run build -``` - -### Type Check - -```bash -npm run typecheck -``` - -### Lint - -```bash -npm run lint -npm run lint:fix -``` - -### Test - -```bash -npm run test -npm run test:coverage -``` - ---- - -## Docker - -### Build Image - -```bash -docker build -t mcp-binance-connector:1.0.0 . -``` - -### Run Container - -```bash -docker run -d \ - --name mcp-binance-connector \ - -p 3606:3606 \ - -e BINANCE_API_KEY=your_key \ - -e BINANCE_API_SECRET=your_secret \ - -e BINANCE_TESTNET=true \ - mcp-binance-connector:1.0.0 -``` - ---- - -## Integration with Claude - -### MCP Configuration - -Add to your Claude/MCP configuration: - -```json -{ - "mcpServers": { - "binance": { - "url": "http://localhost:3606", - "transport": "http" - } - } -} -``` - -### Example Agent Prompts - -``` -"What's the current Bitcoin price?" - -> Uses binance_get_ticker({ symbol: "BTCUSDT" }) - -"Show me the ETH order book" - -> Uses binance_get_orderbook({ symbol: "ETHUSDT" }) - -"Get the last 50 hourly candles for BTC" - -> Uses binance_get_klines({ symbol: "BTCUSDT", interval: "1h", limit: 50 }) - -"Check my Binance balance" - -> Uses binance_get_account() - -"Buy 0.01 BTC at market price" - -> Uses binance_create_order({ symbol: "BTCUSDT", side: "buy", type: "market", amount: 0.01 }) -``` - ---- - -## Risk Management - -The connector includes built-in risk checks: - -1. **Maximum Order Value**: Orders exceeding `MAX_ORDER_VALUE_USDT` are rejected -2. **Daily Volume Limit**: Trading stops when `MAX_DAILY_VOLUME_USDT` is reached -3. **Balance Check**: Buy orders verify sufficient balance -4. **Testnet Default**: Testnet is enabled by default for safety -5. **High-Risk Confirmation**: Orders require explicit confirmation flag - ---- - -## Dependencies - -### Runtime -- `express` - HTTP server -- `ccxt` - Cryptocurrency exchange library -- `zod` - Input validation -- `winston` - Logging -- `dotenv` - Environment configuration -- `@modelcontextprotocol/sdk` - MCP protocol - -### Development -- `typescript` - Type safety -- `ts-node-dev` - Development server -- `jest` - Testing framework -- `eslint` - Code linting - ---- - -## Prerequisites - -1. **Binance Account** with API keys (optional for public data) -2. **Testnet API Keys** for testing (recommended) -3. **Node.js** >= 20.0.0 - -### Getting Binance API Keys - -1. Log into [Binance](https://www.binance.com) -2. Go to API Management -3. Create a new API key -4. Enable Spot Trading permissions -5. (Optional) For testnet: [Binance Testnet](https://testnet.binance.vision/) - ---- - -## Troubleshooting - -### Cannot connect to Binance - -```bash -# Check connectivity -curl https://api.binance.com/api/v3/ping - -# If using testnet, check testnet connectivity -curl https://testnet.binance.vision/api/v3/ping -``` - -### Authentication errors - -```bash -# Verify API keys are set -cat .env | grep BINANCE - -# Check health endpoint for config status -curl http://localhost:3606/health -``` - -### Order rejected by risk check - -The order may exceed configured limits. Check: -- `MAX_ORDER_VALUE_USDT` - single order limit -- `MAX_DAILY_VOLUME_USDT` - daily trading limit -- Available balance for buy orders - ---- - -## References - -- [MCP Protocol](https://modelcontextprotocol.io) -- [CCXT Documentation](https://docs.ccxt.com) -- [Binance API](https://binance-docs.github.io/apidocs/) -- Architecture: `/docs/01-arquitectura/MCP-BINANCE-CONNECTOR-SPEC.md` -- MT4 Connector: `/apps/mcp-mt4-connector/` (reference implementation) - ---- - -**Maintained by:** @PERFIL_MCP_DEVELOPER -**Project:** Trading Platform diff --git a/apps/mcp-binance-connector/package.json b/apps/mcp-binance-connector/package.json deleted file mode 100644 index e3a0ea7..0000000 --- a/apps/mcp-binance-connector/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "mcp-binance-connector", - "version": "1.0.0", - "description": "MCP Server for Binance trading operations via CCXT", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "build": "tsc", - "start": "node dist/index.js", - "dev": "ts-node-dev --respawn src/index.ts", - "test": "jest", - "test:watch": "jest --watch", - "test:coverage": "jest --coverage", - "lint": "eslint src/**/*.ts", - "lint:fix": "eslint src/**/*.ts --fix", - "typecheck": "tsc --noEmit", - "health-check": "curl -s http://localhost:${PORT:-3606}/health || echo 'Server not running'" - }, - "keywords": [ - "mcp", - "model-context-protocol", - "anthropic", - "claude", - "binance", - "crypto", - "trading", - "ccxt" - ], - "author": "Trading Platform Trading Platform", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.0", - "ccxt": "^4.0.0", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "winston": "^3.11.0", - "zod": "^3.22.4" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/jest": "^29.5.11", - "@types/node": "^20.10.0", - "@typescript-eslint/eslint-plugin": "^6.13.0", - "@typescript-eslint/parser": "^6.13.0", - "eslint": "^8.54.0", - "jest": "^29.7.0", - "ts-jest": "^29.1.1", - "ts-node-dev": "^2.0.0", - "typescript": "^5.3.0" - }, - "engines": { - "node": ">=20.0.0" - } -} diff --git a/apps/mcp-binance-connector/src/config.ts b/apps/mcp-binance-connector/src/config.ts deleted file mode 100644 index 0cee051..0000000 --- a/apps/mcp-binance-connector/src/config.ts +++ /dev/null @@ -1,159 +0,0 @@ -/** - * Configuration Module - * - * Manages environment variables and creates Binance clients via CCXT. - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import ccxt from 'ccxt'; -import dotenv from 'dotenv'; - -// Load environment variables -dotenv.config(); - -// ========================================== -// Configuration Interface -// ========================================== - -export interface BinanceConfig { - apiKey: string; - apiSecret: string; - testnet: boolean; - futuresTestnet: boolean; - timeout: number; -} - -export interface RiskConfig { - maxOrderValueUsdt: number; - maxDailyVolumeUsdt: number; - maxLeverage: number; - maxPositionSizePct: number; -} - -export interface ServerConfig { - port: number; - nodeEnv: string; - mcpApiKey: string; - logLevel: string; -} - -// ========================================== -// Configuration Loading -// ========================================== - -export const binanceConfig: BinanceConfig = { - apiKey: process.env.BINANCE_API_KEY || '', - apiSecret: process.env.BINANCE_API_SECRET || '', - testnet: process.env.BINANCE_TESTNET === 'true', - futuresTestnet: process.env.BINANCE_FUTURES_TESTNET === 'true', - timeout: parseInt(process.env.REQUEST_TIMEOUT || '10000', 10), -}; - -export const riskConfig: RiskConfig = { - maxOrderValueUsdt: parseFloat(process.env.MAX_ORDER_VALUE_USDT || '1000'), - maxDailyVolumeUsdt: parseFloat(process.env.MAX_DAILY_VOLUME_USDT || '10000'), - maxLeverage: parseInt(process.env.MAX_LEVERAGE || '20', 10), - maxPositionSizePct: parseFloat(process.env.MAX_POSITION_SIZE_PCT || '5'), -}; - -export const serverConfig: ServerConfig = { - port: parseInt(process.env.PORT || '3606', 10), - nodeEnv: process.env.NODE_ENV || 'development', - mcpApiKey: process.env.MCP_API_KEY || '', - logLevel: process.env.LOG_LEVEL || 'info', -}; - -// ========================================== -// Binance Client Factory -// ========================================== - -/** - * Create a Binance Spot client - */ -export function createBinanceSpotClient(): ccxt.binance { - const isTestnet = binanceConfig.testnet; - - const client = new ccxt.binance({ - apiKey: binanceConfig.apiKey, - secret: binanceConfig.apiSecret, - sandbox: isTestnet, - options: { - defaultType: 'spot', - adjustForTimeDifference: true, - }, - enableRateLimit: true, - rateLimit: 100, - timeout: binanceConfig.timeout, - }); - - return client; -} - -/** - * Create a Binance Futures client - */ -export function createBinanceFuturesClient(): ccxt.binance { - const isTestnet = binanceConfig.futuresTestnet; - - const client = new ccxt.binance({ - apiKey: binanceConfig.apiKey, - secret: binanceConfig.apiSecret, - sandbox: isTestnet, - options: { - defaultType: 'future', - adjustForTimeDifference: true, - }, - enableRateLimit: true, - rateLimit: 100, - timeout: binanceConfig.timeout, - }); - - return client; -} - -// ========================================== -// Configuration Validation -// ========================================== - -export function validateConfig(): { valid: boolean; errors: string[] } { - const errors: string[] = []; - - // Binance API keys are optional for public endpoints - // but required for account/trading operations - if (!binanceConfig.apiKey && serverConfig.nodeEnv === 'production') { - errors.push('BINANCE_API_KEY is required in production'); - } - - if (!binanceConfig.apiSecret && serverConfig.nodeEnv === 'production') { - errors.push('BINANCE_API_SECRET is required in production'); - } - - // Validate risk limits - if (riskConfig.maxOrderValueUsdt <= 0) { - errors.push('MAX_ORDER_VALUE_USDT must be positive'); - } - - if (riskConfig.maxLeverage < 1 || riskConfig.maxLeverage > 125) { - errors.push('MAX_LEVERAGE must be between 1 and 125'); - } - - return { - valid: errors.length === 0, - errors, - }; -} - -// ========================================== -// Exports -// ========================================== - -export default { - binance: binanceConfig, - risk: riskConfig, - server: serverConfig, - createBinanceSpotClient, - createBinanceFuturesClient, - validateConfig, -}; diff --git a/apps/mcp-binance-connector/src/index.ts b/apps/mcp-binance-connector/src/index.ts deleted file mode 100644 index e0df808..0000000 --- a/apps/mcp-binance-connector/src/index.ts +++ /dev/null @@ -1,332 +0,0 @@ -/** - * MCP Server: Binance Connector - * - * Exposes Binance trading capabilities as MCP tools for AI agents. - * Uses CCXT library to communicate with Binance API. - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import express, { Request, Response, NextFunction } from 'express'; -import dotenv from 'dotenv'; -import { mcpToolSchemas, toolHandlers, getAllToolDefinitions, toolRequiresConfirmation, getToolRiskLevel } from './tools'; -import { getBinanceClient } from './services/binance-client'; -import { serverConfig, binanceConfig, validateConfig } from './config'; -import { logger } from './utils/logger'; - -// Load environment variables -dotenv.config(); - -const app = express(); -const PORT = serverConfig.port; -const SERVICE_NAME = 'mcp-binance-connector'; -const VERSION = '1.0.0'; - -// ========================================== -// Middleware -// ========================================== - -app.use(express.json()); - -// Request logging -app.use((req: Request, _res: Response, next: NextFunction) => { - logger.info(`${req.method} ${req.path}`, { - ip: req.ip, - userAgent: req.get('user-agent'), - }); - next(); -}); - -// MCP API Key authentication (optional, for protected endpoints) -const authMiddleware = (req: Request, res: Response, next: NextFunction) => { - const mcpKey = req.headers['x-mcp-api-key']; - - // Skip auth if MCP_API_KEY is not configured - if (!serverConfig.mcpApiKey) { - next(); - return; - } - - if (mcpKey !== serverConfig.mcpApiKey) { - res.status(401).json({ error: 'Invalid MCP API key' }); - return; - } - - next(); -}; - -// ========================================== -// Health & Status Endpoints -// ========================================== - -/** - * Health check endpoint - */ -app.get('/health', async (_req: Request, res: Response) => { - try { - const client = getBinanceClient(); - const binanceConnected = await client.isConnected(); - const binanceConfigured = client.isConfigured(); - - res.json({ - status: binanceConnected ? 'healthy' : 'degraded', - service: SERVICE_NAME, - version: VERSION, - timestamp: new Date().toISOString(), - testnet: binanceConfig.testnet, - dependencies: { - binance: binanceConnected ? 'connected' : 'disconnected', - binanceApiConfigured: binanceConfigured, - }, - }); - } catch (error) { - res.json({ - status: 'unhealthy', - service: SERVICE_NAME, - version: VERSION, - timestamp: new Date().toISOString(), - testnet: binanceConfig.testnet, - error: error instanceof Error ? error.message : 'Unknown error', - }); - } -}); - -/** - * List available MCP tools - */ -app.get('/tools', (_req: Request, res: Response) => { - res.json({ - tools: mcpToolSchemas.map((tool) => ({ - name: tool.name, - description: tool.description, - riskLevel: (tool as { riskLevel?: string }).riskLevel, - requiresConfirmation: (tool as { requiresConfirmation?: boolean }).requiresConfirmation, - })), - count: mcpToolSchemas.length, - }); -}); - -/** - * Get specific tool schema - */ -app.get('/tools/:toolName', (req: Request, res: Response) => { - const { toolName } = req.params; - const tool = mcpToolSchemas.find((t) => t.name === toolName); - - if (!tool) { - res.status(404).json({ - error: `Tool '${toolName}' not found`, - availableTools: mcpToolSchemas.map((t) => t.name), - }); - return; - } - - res.json(tool); -}); - -// ========================================== -// MCP Tool Execution Endpoints -// ========================================== - -/** - * Execute an MCP tool - * POST /tools/:toolName - * Body: { parameters: {...} } - */ -app.post('/tools/:toolName', authMiddleware, async (req: Request, res: Response) => { - const { toolName } = req.params; - const { parameters = {} } = req.body; - - // Validate tool exists - const handler = toolHandlers[toolName]; - if (!handler) { - res.status(404).json({ - success: false, - error: `Tool '${toolName}' not found`, - availableTools: Object.keys(toolHandlers), - }); - return; - } - - try { - logger.info(`Executing tool: ${toolName}`, { - parameters, - riskLevel: getToolRiskLevel(toolName), - requiresConfirmation: toolRequiresConfirmation(toolName), - }); - - const result = await handler(parameters); - - res.json({ - success: true, - tool: toolName, - result, - }); - } catch (error) { - logger.error(`Tool execution failed: ${toolName}`, { error, parameters }); - - // Handle Zod validation errors - if (error && typeof error === 'object' && 'issues' in error) { - res.status(400).json({ - success: false, - error: 'Validation error', - details: (error as { issues: unknown[] }).issues, - }); - return; - } - - res.status(500).json({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - }); - } -}); - -// ========================================== -// MCP Protocol Endpoints (Standard) -// ========================================== - -/** - * MCP Initialize - * Returns server capabilities - */ -app.post('/mcp/initialize', (_req: Request, res: Response) => { - res.json({ - protocolVersion: '2024-11-05', - capabilities: { - tools: {}, - }, - serverInfo: { - name: SERVICE_NAME, - version: VERSION, - }, - }); -}); - -/** - * MCP List Tools - * Returns all available tools in MCP format - */ -app.post('/mcp/tools/list', (_req: Request, res: Response) => { - res.json({ - tools: getAllToolDefinitions(), - }); -}); - -/** - * MCP Call Tool - * Execute a tool with parameters - */ -app.post('/mcp/tools/call', authMiddleware, async (req: Request, res: Response) => { - const { name, arguments: args = {} } = req.body; - - if (!name) { - res.status(400).json({ - error: { - code: 'invalid_request', - message: 'Tool name is required', - }, - }); - return; - } - - const handler = toolHandlers[name]; - if (!handler) { - res.status(404).json({ - error: { - code: 'unknown_tool', - message: `Tool '${name}' not found`, - }, - }); - return; - } - - try { - const result = await handler(args); - res.json(result); - } catch (error) { - // Handle Zod validation errors - if (error && typeof error === 'object' && 'issues' in error) { - res.status(400).json({ - error: { - code: 'invalid_params', - message: 'Invalid tool parameters', - data: (error as { issues: unknown[] }).issues, - }, - }); - return; - } - - res.status(500).json({ - error: { - code: 'internal_error', - message: error instanceof Error ? error.message : 'Unknown error', - }, - }); - } -}); - -// ========================================== -// Error Handler -// ========================================== - -app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { - logger.error('Unhandled error', { error: err }); - res.status(500).json({ - error: 'Internal server error', - message: err.message, - }); -}); - -// ========================================== -// Start Server -// ========================================== - -// Validate configuration before starting -const configValidation = validateConfig(); -if (!configValidation.valid) { - logger.warn('Configuration warnings', { errors: configValidation.errors }); -} - -app.listen(PORT, () => { - console.log(''); - console.log('================================================================'); - console.log(' MCP Binance Connector - Trading Platform Trading Platform '); - console.log('================================================================'); - console.log(` Service: ${SERVICE_NAME}`); - console.log(` Version: ${VERSION}`); - console.log(` Port: ${PORT}`); - console.log(` Environment: ${serverConfig.nodeEnv}`); - console.log(` Testnet Mode: ${binanceConfig.testnet ? 'ENABLED' : 'DISABLED'}`); - console.log(` API Configured: ${binanceConfig.apiKey ? 'Yes' : 'No'}`); - console.log('----------------------------------------------------------------'); - console.log(' Endpoints:'); - console.log(` - Health: http://localhost:${PORT}/health`); - console.log(` - Tools: http://localhost:${PORT}/tools`); - console.log('----------------------------------------------------------------'); - console.log(' MCP Tools Available:'); - mcpToolSchemas.forEach((tool) => { - const risk = (tool as { riskLevel?: string }).riskLevel || 'N/A'; - const confirm = (tool as { requiresConfirmation?: boolean }).requiresConfirmation ? ' (!)' : ''; - console.log(` - ${tool.name} [${risk}]${confirm}`); - }); - console.log('================================================================'); - console.log(''); -}); - -// ========================================== -// Graceful Shutdown -// ========================================== - -process.on('SIGTERM', () => { - logger.info('Received SIGTERM, shutting down gracefully...'); - process.exit(0); -}); - -process.on('SIGINT', () => { - logger.info('Received SIGINT, shutting down gracefully...'); - process.exit(0); -}); - -export default app; diff --git a/apps/mcp-binance-connector/src/middleware/risk-check.ts b/apps/mcp-binance-connector/src/middleware/risk-check.ts deleted file mode 100644 index 7bf810b..0000000 --- a/apps/mcp-binance-connector/src/middleware/risk-check.ts +++ /dev/null @@ -1,209 +0,0 @@ -/** - * Risk Check Middleware - * - * Pre-trade risk validation to ensure orders comply with risk limits. - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import { riskConfig } from '../config'; -import { getBinanceClient } from '../services/binance-client'; -import { logger } from '../utils/logger'; - -// ========================================== -// Types -// ========================================== - -export interface RiskCheckParams { - symbol: string; - side: 'buy' | 'sell'; - amount: number; - price?: number; -} - -export interface RiskCheckResult { - allowed: boolean; - reason?: string; - warnings?: string[]; - orderValue?: number; -} - -// Daily volume tracking (in-memory, resets on restart) -let dailyVolume = 0; -let lastVolumeResetDate = new Date().toDateString(); - -// ========================================== -// Risk Check Functions -// ========================================== - -/** - * Reset daily volume counter at midnight - */ -function checkAndResetDailyVolume(): void { - const today = new Date().toDateString(); - if (today !== lastVolumeResetDate) { - dailyVolume = 0; - lastVolumeResetDate = today; - logger.info('Daily volume counter reset'); - } -} - -/** - * Get the quote asset from a symbol (e.g., USDT from BTCUSDT) - */ -function getQuoteAsset(symbol: string): string { - const stablecoins = ['USDT', 'BUSD', 'USDC', 'TUSD', 'DAI']; - for (const stable of stablecoins) { - if (symbol.endsWith(stable)) { - return stable; - } - } - return 'USDT'; -} - -/** - * Perform comprehensive risk check before order execution - */ -export async function performRiskCheck(params: RiskCheckParams): Promise { - const { symbol, side, amount, price } = params; - const warnings: string[] = []; - - try { - checkAndResetDailyVolume(); - - const client = getBinanceClient(); - - // 1. Get current price if not provided - let orderPrice = price; - if (!orderPrice) { - try { - orderPrice = await client.getCurrentPrice(symbol); - } catch (error) { - logger.warn(`Could not fetch current price for ${symbol}, using amount as value estimate`); - orderPrice = 1; // Fallback - } - } - - // 2. Calculate order value in quote currency (usually USDT) - const orderValue = amount * orderPrice; - - // 3. Check maximum order value - if (orderValue > riskConfig.maxOrderValueUsdt) { - return { - allowed: false, - reason: `Order value ${orderValue.toFixed(2)} USDT exceeds maximum ${riskConfig.maxOrderValueUsdt} USDT`, - orderValue, - }; - } - - // 4. Check daily volume limit - if (dailyVolume + orderValue > riskConfig.maxDailyVolumeUsdt) { - return { - allowed: false, - reason: `Daily volume limit reached. Current: ${dailyVolume.toFixed(2)} USDT, Limit: ${riskConfig.maxDailyVolumeUsdt} USDT`, - orderValue, - }; - } - - // 5. Check if API keys are configured for trading - if (!client.isConfigured()) { - return { - allowed: false, - reason: 'Binance API keys are not configured. Cannot execute trades.', - orderValue, - }; - } - - // 6. Verify we can connect to Binance - const connected = await client.isConnected(); - if (!connected) { - return { - allowed: false, - reason: 'Cannot connect to Binance. Please check your network and API configuration.', - orderValue, - }; - } - - // 7. Check balance for buy orders (if we have account access) - if (side === 'buy') { - try { - const account = await client.getAccount(); - const quoteAsset = getQuoteAsset(symbol); - const quoteBalance = account.balances.find(b => b.asset === quoteAsset); - const available = quoteBalance?.free ?? 0; - - if (available < orderValue) { - return { - allowed: false, - reason: `Insufficient ${quoteAsset} balance. Required: ${orderValue.toFixed(2)}, Available: ${available.toFixed(2)}`, - orderValue, - }; - } - - // Warning if using more than 50% of available balance - if (orderValue > available * 0.5) { - warnings.push(`This order uses ${((orderValue / available) * 100).toFixed(1)}% of your available ${quoteAsset}`); - } - } catch (error) { - warnings.push('Could not verify account balance'); - logger.warn('Balance check failed', { error }); - } - } - - // 8. Check for large order warning - if (orderValue > riskConfig.maxOrderValueUsdt * 0.5) { - warnings.push(`Large order: ${orderValue.toFixed(2)} USDT (${((orderValue / riskConfig.maxOrderValueUsdt) * 100).toFixed(0)}% of max)`); - } - - // All checks passed - return { - allowed: true, - orderValue, - warnings: warnings.length > 0 ? warnings : undefined, - }; - } catch (error) { - const message = error instanceof Error ? error.message : 'Unknown error'; - logger.error('Risk check failed', { error, params }); - return { - allowed: false, - reason: `Risk check error: ${message}`, - }; - } -} - -/** - * Record executed trade volume - */ -export function recordTradeVolume(orderValue: number): void { - checkAndResetDailyVolume(); - dailyVolume += orderValue; - logger.info(`Trade recorded. Daily volume: ${dailyVolume.toFixed(2)} USDT`); -} - -/** - * Get current daily volume - */ -export function getDailyVolume(): number { - checkAndResetDailyVolume(); - return dailyVolume; -} - -/** - * Get remaining daily volume allowance - */ -export function getRemainingDailyVolume(): number { - checkAndResetDailyVolume(); - return Math.max(0, riskConfig.maxDailyVolumeUsdt - dailyVolume); -} - -// ========================================== -// Exports -// ========================================== - -export default { - performRiskCheck, - recordTradeVolume, - getDailyVolume, - getRemainingDailyVolume, -}; diff --git a/apps/mcp-binance-connector/src/services/binance-client.ts b/apps/mcp-binance-connector/src/services/binance-client.ts deleted file mode 100644 index 56d20ca..0000000 --- a/apps/mcp-binance-connector/src/services/binance-client.ts +++ /dev/null @@ -1,471 +0,0 @@ -/** - * Binance Client Service - * - * CCXT wrapper for Binance operations. - * Provides a unified interface for both Spot and Futures trading. - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import ccxt, { Ticker, OrderBook, OHLCV, Balance, Order, Trade } from 'ccxt'; -import { createBinanceSpotClient, createBinanceFuturesClient, binanceConfig } from '../config'; -import { logger } from '../utils/logger'; - -// ========================================== -// Types -// ========================================== - -export interface BinanceTicker { - symbol: string; - price: number; - bid: number; - ask: number; - high24h: number; - low24h: number; - volume24h: number; - change24h: number; - timestamp: number; -} - -export interface BinanceOrderBook { - symbol: string; - bids: [number, number][]; - asks: [number, number][]; - spread: number; - spreadPercentage: number; - timestamp: number; -} - -export interface BinanceKline { - timestamp: number; - open: number; - high: number; - low: number; - close: number; - volume: number; -} - -export interface BinanceAccountBalance { - asset: string; - free: number; - locked: number; - total: number; -} - -export interface BinanceAccount { - accountType: string; - balances: BinanceAccountBalance[]; - canTrade: boolean; - canWithdraw: boolean; - updateTime: number; -} - -export interface BinanceOrder { - id: string; - symbol: string; - side: string; - type: string; - price: number | null; - amount: number; - filled: number; - remaining: number; - status: string; - createdAt: number; -} - -export interface CreateOrderParams { - symbol: string; - side: 'buy' | 'sell'; - type: 'market' | 'limit' | 'stop_loss' | 'take_profit'; - amount: number; - price?: number; - stopPrice?: number; -} - -export interface OrderResult { - success: boolean; - order?: BinanceOrder; - error?: string; -} - -// ========================================== -// Binance Client Class -// ========================================== - -export class BinanceClient { - private spotClient: ccxt.binance; - private futuresClient: ccxt.binance; - private marketsLoaded: boolean = false; - - constructor() { - this.spotClient = createBinanceSpotClient(); - this.futuresClient = createBinanceFuturesClient(); - } - - /** - * Check if client is properly configured - */ - isConfigured(): boolean { - return binanceConfig.apiKey !== '' && binanceConfig.apiSecret !== ''; - } - - /** - * Test connectivity to Binance - */ - async isConnected(): Promise { - try { - await this.spotClient.fetchTime(); - return true; - } catch { - return false; - } - } - - /** - * Load markets if not already loaded - */ - private async ensureMarketsLoaded(): Promise { - if (!this.marketsLoaded) { - await this.spotClient.loadMarkets(); - this.marketsLoaded = true; - } - } - - // ========================================== - // Market Data Methods - // ========================================== - - /** - * Get ticker for a symbol - */ - async getTicker(symbol: string): Promise { - try { - await this.ensureMarketsLoaded(); - const ticker: Ticker = await this.spotClient.fetchTicker(symbol); - - return { - symbol: ticker.symbol, - price: ticker.last ?? 0, - bid: ticker.bid ?? 0, - ask: ticker.ask ?? 0, - high24h: ticker.high ?? 0, - low24h: ticker.low ?? 0, - volume24h: ticker.baseVolume ?? 0, - change24h: ticker.percentage ?? 0, - timestamp: ticker.timestamp ?? Date.now(), - }; - } catch (error) { - logger.error(`Failed to get ticker for ${symbol}`, { error }); - throw error; - } - } - - /** - * Get order book for a symbol - */ - async getOrderBook(symbol: string, limit: number = 20): Promise { - try { - await this.ensureMarketsLoaded(); - const orderbook: OrderBook = await this.spotClient.fetchOrderBook(symbol, limit); - - const topBid = orderbook.bids[0]?.[0] ?? 0; - const topAsk = orderbook.asks[0]?.[0] ?? 0; - const spread = topAsk - topBid; - const spreadPercentage = topBid > 0 ? (spread / topBid) * 100 : 0; - - return { - symbol, - bids: orderbook.bids.slice(0, limit) as [number, number][], - asks: orderbook.asks.slice(0, limit) as [number, number][], - spread, - spreadPercentage, - timestamp: orderbook.timestamp ?? Date.now(), - }; - } catch (error) { - logger.error(`Failed to get order book for ${symbol}`, { error }); - throw error; - } - } - - /** - * Get OHLCV (klines/candles) for a symbol - */ - async getKlines( - symbol: string, - interval: string = '5m', - limit: number = 100 - ): Promise { - try { - await this.ensureMarketsLoaded(); - const ohlcv: OHLCV[] = await this.spotClient.fetchOHLCV(symbol, interval, undefined, limit); - - return ohlcv.map((candle) => ({ - timestamp: candle[0] as number, - open: candle[1] as number, - high: candle[2] as number, - low: candle[3] as number, - close: candle[4] as number, - volume: candle[5] as number, - })); - } catch (error) { - logger.error(`Failed to get klines for ${symbol}`, { error }); - throw error; - } - } - - // ========================================== - // Account Methods - // ========================================== - - /** - * Get account balance - */ - async getAccount(): Promise { - try { - if (!this.isConfigured()) { - throw new Error('Binance API keys not configured'); - } - - const balance: Balance = await this.spotClient.fetchBalance(); - - // Filter non-zero balances - const balances: BinanceAccountBalance[] = Object.entries(balance.total) - .filter(([_, amount]) => (amount as number) > 0) - .map(([asset, total]) => ({ - asset, - free: (balance.free[asset] as number) ?? 0, - locked: (balance.used[asset] as number) ?? 0, - total: total as number, - })); - - return { - accountType: 'SPOT', - balances, - canTrade: true, - canWithdraw: true, - updateTime: Date.now(), - }; - } catch (error) { - logger.error('Failed to get account info', { error }); - throw error; - } - } - - /** - * Get open orders - */ - async getOpenOrders(symbol?: string): Promise { - try { - if (!this.isConfigured()) { - throw new Error('Binance API keys not configured'); - } - - const orders: Order[] = await this.spotClient.fetchOpenOrders(symbol); - - return orders.map((order) => ({ - id: order.id, - symbol: order.symbol, - side: order.side, - type: order.type, - price: order.price, - amount: order.amount, - filled: order.filled, - remaining: order.remaining, - status: order.status, - createdAt: order.timestamp ?? Date.now(), - })); - } catch (error) { - logger.error('Failed to get open orders', { error }); - throw error; - } - } - - /** - * Get trade history - */ - async getTradeHistory(symbol: string, limit: number = 50): Promise { - try { - if (!this.isConfigured()) { - throw new Error('Binance API keys not configured'); - } - - return await this.spotClient.fetchMyTrades(symbol, undefined, limit); - } catch (error) { - logger.error(`Failed to get trade history for ${symbol}`, { error }); - throw error; - } - } - - // ========================================== - // Order Methods - // ========================================== - - /** - * Create a new order - */ - async createOrder(params: CreateOrderParams): Promise { - try { - if (!this.isConfigured()) { - throw new Error('Binance API keys not configured'); - } - - await this.ensureMarketsLoaded(); - - let order: Order; - - switch (params.type) { - case 'market': - order = await this.spotClient.createMarketOrder( - params.symbol, - params.side, - params.amount - ); - break; - - case 'limit': - if (!params.price) { - return { success: false, error: 'Price is required for limit orders' }; - } - order = await this.spotClient.createLimitOrder( - params.symbol, - params.side, - params.amount, - params.price - ); - break; - - case 'stop_loss': - if (!params.stopPrice) { - return { success: false, error: 'Stop price is required for stop loss orders' }; - } - order = await this.spotClient.createOrder( - params.symbol, - 'stop_loss', - params.side, - params.amount, - undefined, - { stopPrice: params.stopPrice } - ); - break; - - case 'take_profit': - if (!params.stopPrice) { - return { success: false, error: 'Stop price is required for take profit orders' }; - } - order = await this.spotClient.createOrder( - params.symbol, - 'take_profit', - params.side, - params.amount, - undefined, - { stopPrice: params.stopPrice } - ); - break; - - default: - return { success: false, error: `Unsupported order type: ${params.type}` }; - } - - return { - success: true, - order: { - id: order.id, - symbol: order.symbol, - side: order.side, - type: order.type, - price: order.price ?? order.average ?? null, - amount: order.amount, - filled: order.filled, - remaining: order.remaining, - status: order.status, - createdAt: order.timestamp ?? Date.now(), - }, - }; - } catch (error) { - const message = error instanceof Error ? error.message : 'Unknown error'; - logger.error('Failed to create order', { error, params }); - return { success: false, error: message }; - } - } - - /** - * Cancel an order - */ - async cancelOrder(orderId: string, symbol: string): Promise { - try { - if (!this.isConfigured()) { - throw new Error('Binance API keys not configured'); - } - - const result = await this.spotClient.cancelOrder(orderId, symbol); - - return { - success: true, - order: { - id: result.id, - symbol: result.symbol, - side: result.side, - type: result.type, - price: result.price, - amount: result.amount, - filled: result.filled, - remaining: result.remaining, - status: 'CANCELLED', - createdAt: result.timestamp ?? Date.now(), - }, - }; - } catch (error) { - const message = error instanceof Error ? error.message : 'Unknown error'; - logger.error('Failed to cancel order', { error, orderId, symbol }); - return { success: false, error: message }; - } - } - - /** - * Cancel all orders for a symbol - */ - async cancelAllOrders(symbol: string): Promise<{ success: boolean; cancelledCount: number; error?: string }> { - try { - if (!this.isConfigured()) { - throw new Error('Binance API keys not configured'); - } - - const result = await this.spotClient.cancelAllOrders(symbol); - - return { - success: true, - cancelledCount: Array.isArray(result) ? result.length : 0, - }; - } catch (error) { - const message = error instanceof Error ? error.message : 'Unknown error'; - logger.error('Failed to cancel all orders', { error, symbol }); - return { success: false, cancelledCount: 0, error: message }; - } - } - - /** - * Get current price for a symbol (helper method) - */ - async getCurrentPrice(symbol: string): Promise { - const ticker = await this.getTicker(symbol); - return ticker.price; - } -} - -// ========================================== -// Singleton Instance -// ========================================== - -let clientInstance: BinanceClient | null = null; - -export function getBinanceClient(): BinanceClient { - if (!clientInstance) { - clientInstance = new BinanceClient(); - } - return clientInstance; -} - -export function resetBinanceClient(): void { - clientInstance = null; -} diff --git a/apps/mcp-binance-connector/src/tools/account.ts b/apps/mcp-binance-connector/src/tools/account.ts deleted file mode 100644 index 444305f..0000000 --- a/apps/mcp-binance-connector/src/tools/account.ts +++ /dev/null @@ -1,265 +0,0 @@ -/** - * Binance Account Tools - * - * - binance_get_account: Get account balance and status - * - binance_get_open_orders: Get all open orders - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import { z } from 'zod'; -import { getBinanceClient, BinanceAccount, BinanceOrder } from '../services/binance-client'; - -// ========================================== -// binance_get_account -// ========================================== - -/** - * Tool: binance_get_account - * Get account balance and status - */ -export const binanceGetAccountSchema = { - name: 'binance_get_account', - description: 'Get Binance account balance and status. Shows all assets with non-zero balance.', - inputSchema: { - type: 'object' as const, - properties: {}, - required: [] as string[], - }, -}; - -export const BinanceGetAccountInputSchema = z.object({}); - -export type BinanceGetAccountInput = z.infer; - -export interface BinanceGetAccountResult { - success: boolean; - data?: BinanceAccount & { totalUsdtEstimate?: number }; - error?: string; -} - -export async function binance_get_account( - _params: BinanceGetAccountInput -): Promise { - try { - const client = getBinanceClient(); - - if (!client.isConfigured()) { - return { - success: false, - error: 'Binance API keys are not configured', - }; - } - - const connected = await client.isConnected(); - if (!connected) { - return { - success: false, - error: 'Cannot connect to Binance. Please check your network.', - }; - } - - const account = await client.getAccount(); - - // Estimate total value in USDT - let totalUsdtEstimate = 0; - for (const balance of account.balances) { - if (balance.asset === 'USDT' || balance.asset === 'BUSD' || balance.asset === 'USDC') { - totalUsdtEstimate += balance.total; - } else if (balance.total > 0) { - try { - const price = await client.getCurrentPrice(`${balance.asset}USDT`); - totalUsdtEstimate += balance.total * price; - } catch { - // Skip if no USDT pair exists - } - } - } - - return { - success: true, - data: { - ...account, - totalUsdtEstimate, - }, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleBinanceGetAccount( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = BinanceGetAccountInputSchema.parse(params); - const result = await binance_get_account(validatedParams); - - if (result.success && result.data) { - const d = result.data; - - // Sort balances by total value - const sortedBalances = [...d.balances].sort((a, b) => { - // USDT first, then by total - if (a.asset === 'USDT') return -1; - if (b.asset === 'USDT') return 1; - return b.total - a.total; - }); - - let balancesStr = sortedBalances - .slice(0, 20) // Top 20 assets - .map((b) => { - const lockedStr = b.locked > 0 ? ` (Locked: ${b.locked.toFixed(8)})` : ''; - return ` ${b.asset.padEnd(8)} Free: ${b.free.toFixed(8)}${lockedStr}`; - }) - .join('\n'); - - const formattedOutput = ` -Binance Account Information -${'='.repeat(35)} -Account Type: ${d.accountType} -Can Trade: ${d.canTrade ? 'Yes' : 'No'} -Can Withdraw: ${d.canWithdraw ? 'Yes' : 'No'} - -Estimated Total Value ---------------------- -~$${d.totalUsdtEstimate?.toFixed(2) ?? 'N/A'} USDT - -Asset Balances (${d.balances.length} with balance) -${'='.repeat(35)} -${balancesStr} -${d.balances.length > 20 ? `\n ... and ${d.balances.length - 20} more assets` : ''} - -Last Update: ${new Date(d.updateTime).toISOString()} -`.trim(); - - return { - content: [{ type: 'text', text: formattedOutput }], - }; - } - - return { - content: [{ type: 'text', text: `Error: ${result.error}` }], - }; -} - -// ========================================== -// binance_get_open_orders -// ========================================== - -/** - * Tool: binance_get_open_orders - * Get all open (pending) orders - */ -export const binanceGetOpenOrdersSchema = { - name: 'binance_get_open_orders', - description: 'Get all open (pending) orders. Optionally filter by symbol.', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Optional: Filter by trading pair symbol (e.g., BTCUSDT)', - }, - }, - required: [] as string[], - }, -}; - -export const BinanceGetOpenOrdersInputSchema = z.object({ - symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()).optional(), -}); - -export type BinanceGetOpenOrdersInput = z.infer; - -export interface BinanceGetOpenOrdersResult { - success: boolean; - data?: { - orders: BinanceOrder[]; - count: number; - }; - error?: string; -} - -export async function binance_get_open_orders( - params: BinanceGetOpenOrdersInput -): Promise { - try { - const client = getBinanceClient(); - - if (!client.isConfigured()) { - return { - success: false, - error: 'Binance API keys are not configured', - }; - } - - const orders = await client.getOpenOrders(params.symbol); - - return { - success: true, - data: { - orders, - count: orders.length, - }, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleBinanceGetOpenOrders( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = BinanceGetOpenOrdersInputSchema.parse(params); - const result = await binance_get_open_orders(validatedParams); - - if (result.success && result.data) { - const d = result.data; - - if (d.count === 0) { - return { - content: [ - { - type: 'text', - text: `No open orders${validatedParams.symbol ? ` for ${validatedParams.symbol}` : ''}`, - }, - ], - }; - } - - let ordersStr = d.orders - .map((o) => { - const priceStr = o.price ? `$${o.price.toFixed(8)}` : 'MARKET'; - const filledPct = o.amount > 0 ? ((o.filled / o.amount) * 100).toFixed(1) : '0'; - return ` #${o.id} - Symbol: ${o.symbol} | ${o.side.toUpperCase()} | ${o.type.toUpperCase()} - Price: ${priceStr} | Amount: ${o.amount.toFixed(8)} - Filled: ${o.filled.toFixed(8)} (${filledPct}%) | Remaining: ${o.remaining.toFixed(8)} - Status: ${o.status} | Created: ${new Date(o.createdAt).toISOString()}`; - }) - .join('\n\n'); - - const formattedOutput = ` -Open Orders${validatedParams.symbol ? ` - ${validatedParams.symbol}` : ''} -${'='.repeat(35)} -Total Orders: ${d.count} - -${ordersStr} -`.trim(); - - return { - content: [{ type: 'text', text: formattedOutput }], - }; - } - - return { - content: [{ type: 'text', text: `Error: ${result.error}` }], - }; -} diff --git a/apps/mcp-binance-connector/src/tools/index.ts b/apps/mcp-binance-connector/src/tools/index.ts deleted file mode 100644 index 4a838e8..0000000 --- a/apps/mcp-binance-connector/src/tools/index.ts +++ /dev/null @@ -1,288 +0,0 @@ -/** - * MCP Tools Index - * - * Exports all Binance MCP tools and their schemas for registration - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -// Import handlers for use in toolHandlers map -import { handleBinanceGetTicker, handleBinanceGetOrderbook, handleBinanceGetKlines } from './market'; -import { handleBinanceGetAccount, handleBinanceGetOpenOrders } from './account'; -import { handleBinanceCreateOrder, handleBinanceCancelOrder } from './orders'; - -// ========================================== -// Market Tools Exports -// ========================================== - -export { - binanceGetTickerSchema, - binance_get_ticker, - handleBinanceGetTicker, - BinanceGetTickerInputSchema, - type BinanceGetTickerInput, - type BinanceGetTickerResult, - binanceGetOrderbookSchema, - binance_get_orderbook, - handleBinanceGetOrderbook, - BinanceGetOrderbookInputSchema, - type BinanceGetOrderbookInput, - type BinanceGetOrderbookResult, - binanceGetKlinesSchema, - binance_get_klines, - handleBinanceGetKlines, - BinanceGetKlinesInputSchema, - type BinanceGetKlinesInput, - type BinanceGetKlinesResult, -} from './market'; - -// ========================================== -// Account Tools Exports -// ========================================== - -export { - binanceGetAccountSchema, - binance_get_account, - handleBinanceGetAccount, - BinanceGetAccountInputSchema, - type BinanceGetAccountInput, - type BinanceGetAccountResult, - binanceGetOpenOrdersSchema, - binance_get_open_orders, - handleBinanceGetOpenOrders, - BinanceGetOpenOrdersInputSchema, - type BinanceGetOpenOrdersInput, - type BinanceGetOpenOrdersResult, -} from './account'; - -// ========================================== -// Order Tools Exports -// ========================================== - -export { - binanceCreateOrderSchema, - binance_create_order, - handleBinanceCreateOrder, - BinanceCreateOrderInputSchema, - type BinanceCreateOrderInput, - type BinanceCreateOrderResult, - binanceCancelOrderSchema, - binance_cancel_order, - handleBinanceCancelOrder, - BinanceCancelOrderInputSchema, - type BinanceCancelOrderInput, - type BinanceCancelOrderResult, -} from './orders'; - -// ========================================== -// Tool Registry -// ========================================== - -/** - * All available MCP tools with their schemas - * Follows MCP protocol format - */ -export const mcpToolSchemas = [ - // Market Data Tools (Low Risk) - { - name: 'binance_get_ticker', - description: 'Get the current price and 24-hour statistics for a Binance trading pair', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT, ETHUSDT, BNBUSDT)', - }, - }, - required: ['symbol'] as string[], - }, - riskLevel: 'LOW', - }, - { - name: 'binance_get_orderbook', - description: 'Get the order book (bids and asks) with the specified depth for a trading pair', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT)', - }, - limit: { - type: 'number', - description: 'Order book depth (5, 10, 20, 50, or 100). Default: 20', - }, - }, - required: ['symbol'] as string[], - }, - riskLevel: 'LOW', - }, - { - name: 'binance_get_klines', - description: 'Get historical candlestick (OHLCV) data for technical analysis', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT)', - }, - interval: { - type: 'string', - description: 'Candle interval: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w. Default: 5m', - enum: ['1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w'], - }, - limit: { - type: 'number', - description: 'Number of candles to retrieve (max 500). Default: 100', - }, - }, - required: ['symbol'] as string[], - }, - riskLevel: 'LOW', - }, - - // Account Tools (Medium Risk) - { - name: 'binance_get_account', - description: 'Get Binance account balance and status. Shows all assets with non-zero balance.', - inputSchema: { - type: 'object' as const, - properties: {}, - required: [] as string[], - }, - riskLevel: 'MEDIUM', - }, - { - name: 'binance_get_open_orders', - description: 'Get all open (pending) orders. Optionally filter by symbol.', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Optional: Filter by trading pair symbol (e.g., BTCUSDT)', - }, - }, - required: [] as string[], - }, - riskLevel: 'MEDIUM', - }, - - // Order Tools (High Risk) - { - name: 'binance_create_order', - description: 'Create a new buy or sell order on Binance. HIGH RISK - Ensure you validate with the user before executing.', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT, ETHUSDT)', - }, - side: { - type: 'string', - enum: ['buy', 'sell'], - description: 'Order direction: buy or sell', - }, - type: { - type: 'string', - enum: ['market', 'limit', 'stop_loss', 'take_profit'], - description: 'Order type. Default: market', - }, - amount: { - type: 'number', - description: 'Amount of the base asset to buy/sell', - }, - price: { - type: 'number', - description: 'Price per unit (required for limit orders)', - }, - stopPrice: { - type: 'number', - description: 'Stop price (required for stop_loss and take_profit orders)', - }, - }, - required: ['symbol', 'side', 'amount'] as string[], - }, - riskLevel: 'HIGH', - requiresConfirmation: true, - }, - { - name: 'binance_cancel_order', - description: 'Cancel a pending order by order ID and symbol', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT)', - }, - orderId: { - type: 'string', - description: 'Order ID to cancel', - }, - }, - required: ['symbol', 'orderId'] as string[], - }, - riskLevel: 'MEDIUM', - }, -]; - -/** - * Tool handler routing map - * Maps tool names to their handler functions - */ -export const toolHandlers: Record< - string, - (params: unknown) => Promise<{ content: Array<{ type: string; text: string }> }> -> = { - // Market tools - binance_get_ticker: handleBinanceGetTicker, - binance_get_orderbook: handleBinanceGetOrderbook, - binance_get_klines: handleBinanceGetKlines, - - // Account tools - binance_get_account: handleBinanceGetAccount, - binance_get_open_orders: handleBinanceGetOpenOrders, - - // Order tools - binance_create_order: handleBinanceCreateOrder, - binance_cancel_order: handleBinanceCancelOrder, -}; - -/** - * Get all tool definitions for MCP protocol - */ -export function getAllToolDefinitions() { - return mcpToolSchemas.map((tool) => ({ - name: tool.name, - description: tool.description, - inputSchema: tool.inputSchema, - })); -} - -/** - * Get tool by name - */ -export function getToolByName(name: string) { - return mcpToolSchemas.find((tool) => tool.name === name); -} - -/** - * Check if a tool requires confirmation - */ -export function toolRequiresConfirmation(name: string): boolean { - const tool = mcpToolSchemas.find((t) => t.name === name); - return (tool as { requiresConfirmation?: boolean })?.requiresConfirmation === true; -} - -/** - * Get tool risk level - */ -export function getToolRiskLevel(name: string): string { - const tool = mcpToolSchemas.find((t) => t.name === name); - return (tool as { riskLevel?: string })?.riskLevel ?? 'UNKNOWN'; -} diff --git a/apps/mcp-binance-connector/src/tools/market.ts b/apps/mcp-binance-connector/src/tools/market.ts deleted file mode 100644 index 5df5344..0000000 --- a/apps/mcp-binance-connector/src/tools/market.ts +++ /dev/null @@ -1,392 +0,0 @@ -/** - * Binance Market Data Tools - * - * - binance_get_ticker: Get current price and 24h stats - * - binance_get_orderbook: Get order book depth - * - binance_get_klines: Get OHLCV candles - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import { z } from 'zod'; -import { getBinanceClient, BinanceTicker, BinanceOrderBook, BinanceKline } from '../services/binance-client'; - -// ========================================== -// binance_get_ticker -// ========================================== - -/** - * Tool: binance_get_ticker - * Get current price and 24h statistics for a trading pair - */ -export const binanceGetTickerSchema = { - name: 'binance_get_ticker', - description: 'Get the current price and 24-hour statistics for a Binance trading pair', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT, ETHUSDT, BNBUSDT)', - }, - }, - required: ['symbol'] as string[], - }, -}; - -export const BinanceGetTickerInputSchema = z.object({ - symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()), -}); - -export type BinanceGetTickerInput = z.infer; - -export interface BinanceGetTickerResult { - success: boolean; - data?: BinanceTicker; - error?: string; -} - -export async function binance_get_ticker( - params: BinanceGetTickerInput -): Promise { - try { - const client = getBinanceClient(); - const ticker = await client.getTicker(params.symbol); - - return { - success: true, - data: ticker, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleBinanceGetTicker( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = BinanceGetTickerInputSchema.parse(params); - const result = await binance_get_ticker(validatedParams); - - if (result.success && result.data) { - const d = result.data; - const changeSymbol = d.change24h >= 0 ? '+' : ''; - - const formattedOutput = ` -Binance Ticker: ${d.symbol} -${'='.repeat(35)} -Current Price: $${d.price.toFixed(getPriceDecimals(d.symbol))} -Bid: $${d.bid.toFixed(getPriceDecimals(d.symbol))} -Ask: $${d.ask.toFixed(getPriceDecimals(d.symbol))} - -24h Statistics --------------- -High: $${d.high24h.toFixed(getPriceDecimals(d.symbol))} -Low: $${d.low24h.toFixed(getPriceDecimals(d.symbol))} -Volume: ${formatVolume(d.volume24h)} -Change: ${changeSymbol}${d.change24h.toFixed(2)}% - -Last Update: ${new Date(d.timestamp).toISOString()} -`.trim(); - - return { - content: [{ type: 'text', text: formattedOutput }], - }; - } - - return { - content: [{ type: 'text', text: `Error: ${result.error}` }], - }; -} - -// ========================================== -// binance_get_orderbook -// ========================================== - -/** - * Tool: binance_get_orderbook - * Get order book (bids and asks) with specified depth - */ -export const binanceGetOrderbookSchema = { - name: 'binance_get_orderbook', - description: 'Get the order book (bids and asks) with the specified depth for a trading pair', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT)', - }, - limit: { - type: 'number', - description: 'Order book depth (5, 10, 20, 50, or 100). Default: 20', - }, - }, - required: ['symbol'] as string[], - }, -}; - -export const BinanceGetOrderbookInputSchema = z.object({ - symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()), - limit: z.number().int().min(5).max(100).default(20), -}); - -export type BinanceGetOrderbookInput = z.infer; - -export interface BinanceGetOrderbookResult { - success: boolean; - data?: BinanceOrderBook; - error?: string; -} - -export async function binance_get_orderbook( - params: BinanceGetOrderbookInput -): Promise { - try { - const client = getBinanceClient(); - const orderbook = await client.getOrderBook(params.symbol, params.limit); - - return { - success: true, - data: orderbook, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleBinanceGetOrderbook( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = BinanceGetOrderbookInputSchema.parse(params); - const result = await binance_get_orderbook(validatedParams); - - if (result.success && result.data) { - const d = result.data; - const decimals = getPriceDecimals(d.symbol); - - // Format top 10 levels - const topBids = d.bids.slice(0, 10); - const topAsks = d.asks.slice(0, 10); - - let bidsStr = topBids - .map(([price, qty]) => ` $${price.toFixed(decimals)} | ${qty.toFixed(6)}`) - .join('\n'); - - let asksStr = topAsks - .map(([price, qty]) => ` $${price.toFixed(decimals)} | ${qty.toFixed(6)}`) - .join('\n'); - - const formattedOutput = ` -Order Book: ${d.symbol} -${'='.repeat(35)} -Spread: $${d.spread.toFixed(decimals)} (${d.spreadPercentage.toFixed(4)}%) - -Top ${topAsks.length} Asks (Sell Orders) -${'-'.repeat(25)} -${asksStr} - -Top ${topBids.length} Bids (Buy Orders) -${'-'.repeat(25)} -${bidsStr} - -Timestamp: ${new Date(d.timestamp).toISOString()} -`.trim(); - - return { - content: [{ type: 'text', text: formattedOutput }], - }; - } - - return { - content: [{ type: 'text', text: `Error: ${result.error}` }], - }; -} - -// ========================================== -// binance_get_klines -// ========================================== - -/** - * Tool: binance_get_klines - * Get historical OHLCV candles for technical analysis - */ -export const binanceGetKlinesSchema = { - name: 'binance_get_klines', - description: 'Get historical candlestick (OHLCV) data for technical analysis', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT)', - }, - interval: { - type: 'string', - description: 'Candle interval: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w. Default: 5m', - enum: ['1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w'], - }, - limit: { - type: 'number', - description: 'Number of candles to retrieve (max 500). Default: 100', - }, - }, - required: ['symbol'] as string[], - }, -}; - -export const BinanceGetKlinesInputSchema = z.object({ - symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()), - interval: z.enum(['1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w']).default('5m'), - limit: z.number().int().min(1).max(500).default(100), -}); - -export type BinanceGetKlinesInput = z.infer; - -export interface BinanceGetKlinesResult { - success: boolean; - data?: { - symbol: string; - interval: string; - candles: BinanceKline[]; - count: number; - }; - error?: string; -} - -export async function binance_get_klines( - params: BinanceGetKlinesInput -): Promise { - try { - const client = getBinanceClient(); - const klines = await client.getKlines(params.symbol, params.interval, params.limit); - - return { - success: true, - data: { - symbol: params.symbol, - interval: params.interval, - candles: klines, - count: klines.length, - }, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleBinanceGetKlines( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = BinanceGetKlinesInputSchema.parse(params); - const result = await binance_get_klines(validatedParams); - - if (result.success && result.data) { - const d = result.data; - const decimals = getPriceDecimals(d.symbol); - - // Get last 5 candles for display - const recentCandles = d.candles.slice(-5); - - let candlesStr = recentCandles - .map((c) => { - const time = new Date(c.timestamp).toISOString().slice(0, 16).replace('T', ' '); - const direction = c.close >= c.open ? 'UP' : 'DOWN'; - return ` ${time} | O:${c.open.toFixed(decimals)} H:${c.high.toFixed(decimals)} L:${c.low.toFixed(decimals)} C:${c.close.toFixed(decimals)} | V:${formatVolume(c.volume)} | ${direction}`; - }) - .join('\n'); - - // Calculate basic stats - const closes = d.candles.map((c) => c.close); - const high = Math.max(...d.candles.map((c) => c.high)); - const low = Math.min(...d.candles.map((c) => c.low)); - const avgVolume = d.candles.reduce((sum, c) => sum + c.volume, 0) / d.candles.length; - - const formattedOutput = ` -Klines: ${d.symbol} (${d.interval}) -${'='.repeat(45)} -Retrieved: ${d.count} candles - -Period Statistics ------------------ -Highest High: $${high.toFixed(decimals)} -Lowest Low: $${low.toFixed(decimals)} -Avg Volume: ${formatVolume(avgVolume)} - -Recent Candles (last 5) ------------------------ -${candlesStr} - -First Candle: ${new Date(d.candles[0].timestamp).toISOString()} -Last Candle: ${new Date(d.candles[d.candles.length - 1].timestamp).toISOString()} -`.trim(); - - return { - content: [{ type: 'text', text: formattedOutput }], - }; - } - - return { - content: [{ type: 'text', text: `Error: ${result.error}` }], - }; -} - -// ========================================== -// Helper Functions -// ========================================== - -/** - * Get appropriate decimal places for price display - */ -function getPriceDecimals(symbol: string): number { - const upper = symbol.toUpperCase(); - - // Stablecoins and fiat pairs - if (upper.includes('USD') && !upper.startsWith('BTC') && !upper.startsWith('ETH')) { - return 4; - } - - // BTC pairs - if (upper === 'BTCUSDT' || upper === 'BTCBUSD') { - return 2; - } - - // ETH pairs - if (upper === 'ETHUSDT' || upper === 'ETHBUSD') { - return 2; - } - - // Small value coins - if (upper.includes('SHIB') || upper.includes('DOGE') || upper.includes('PEPE')) { - return 8; - } - - // Default - return 4; -} - -/** - * Format large volume numbers - */ -function formatVolume(volume: number): string { - if (volume >= 1_000_000_000) { - return `${(volume / 1_000_000_000).toFixed(2)}B`; - } - if (volume >= 1_000_000) { - return `${(volume / 1_000_000).toFixed(2)}M`; - } - if (volume >= 1_000) { - return `${(volume / 1_000).toFixed(2)}K`; - } - return volume.toFixed(4); -} diff --git a/apps/mcp-binance-connector/src/tools/orders.ts b/apps/mcp-binance-connector/src/tools/orders.ts deleted file mode 100644 index 7cb7eae..0000000 --- a/apps/mcp-binance-connector/src/tools/orders.ts +++ /dev/null @@ -1,334 +0,0 @@ -/** - * Binance Order Management Tools - * - * - binance_create_order: Create a new order (HIGH RISK) - * - binance_cancel_order: Cancel a pending order - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import { z } from 'zod'; -import { getBinanceClient, BinanceOrder, CreateOrderParams } from '../services/binance-client'; -import { performRiskCheck, recordTradeVolume } from '../middleware/risk-check'; -import { logger } from '../utils/logger'; - -// ========================================== -// binance_create_order -// ========================================== - -/** - * Tool: binance_create_order - * Create a new buy or sell order - * HIGH RISK - Requires confirmation - */ -export const binanceCreateOrderSchema = { - name: 'binance_create_order', - description: 'Create a new buy or sell order on Binance. HIGH RISK - Ensure you validate with the user before executing.', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT, ETHUSDT)', - }, - side: { - type: 'string', - enum: ['buy', 'sell'], - description: 'Order direction: buy or sell', - }, - type: { - type: 'string', - enum: ['market', 'limit', 'stop_loss', 'take_profit'], - description: 'Order type. Default: market', - }, - amount: { - type: 'number', - description: 'Amount of the base asset to buy/sell', - }, - price: { - type: 'number', - description: 'Price per unit (required for limit orders)', - }, - stopPrice: { - type: 'number', - description: 'Stop price (required for stop_loss and take_profit orders)', - }, - }, - required: ['symbol', 'side', 'amount'] as string[], - }, - riskLevel: 'HIGH', - requiresConfirmation: true, -}; - -export const BinanceCreateOrderInputSchema = z.object({ - symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()), - side: z.enum(['buy', 'sell']), - type: z.enum(['market', 'limit', 'stop_loss', 'take_profit']).default('market'), - amount: z.number().positive(), - price: z.number().positive().optional(), - stopPrice: z.number().positive().optional(), -}); - -export type BinanceCreateOrderInput = z.infer; - -export interface BinanceCreateOrderResult { - success: boolean; - data?: { - order: BinanceOrder; - riskWarnings?: string[]; - }; - error?: string; - riskCheckFailed?: boolean; -} - -export async function binance_create_order( - params: BinanceCreateOrderInput -): Promise { - try { - const client = getBinanceClient(); - - if (!client.isConfigured()) { - return { - success: false, - error: 'Binance API keys are not configured', - }; - } - - // 1. Perform risk check - const riskCheck = await performRiskCheck({ - symbol: params.symbol, - side: params.side, - amount: params.amount, - price: params.price, - }); - - if (!riskCheck.allowed) { - logger.warn('Order rejected by risk check', { - params, - reason: riskCheck.reason, - }); - return { - success: false, - error: riskCheck.reason, - riskCheckFailed: true, - }; - } - - // 2. Validate order parameters - if (params.type === 'limit' && !params.price) { - return { - success: false, - error: 'Price is required for limit orders', - }; - } - - if ((params.type === 'stop_loss' || params.type === 'take_profit') && !params.stopPrice) { - return { - success: false, - error: `Stop price is required for ${params.type} orders`, - }; - } - - // 3. Create the order - const orderParams: CreateOrderParams = { - symbol: params.symbol, - side: params.side, - type: params.type, - amount: params.amount, - price: params.price, - stopPrice: params.stopPrice, - }; - - const result = await client.createOrder(orderParams); - - if (result.success && result.order) { - // Record trade volume for daily limit tracking - if (riskCheck.orderValue) { - recordTradeVolume(riskCheck.orderValue); - } - - logger.info('Order created successfully', { - orderId: result.order.id, - symbol: params.symbol, - side: params.side, - amount: params.amount, - }); - - return { - success: true, - data: { - order: result.order, - riskWarnings: riskCheck.warnings, - }, - }; - } - - return { - success: false, - error: result.error || 'Failed to create order', - }; - } catch (error) { - logger.error('Order creation failed', { error, params }); - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleBinanceCreateOrder( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = BinanceCreateOrderInputSchema.parse(params); - const result = await binance_create_order(validatedParams); - - if (result.success && result.data) { - const o = result.data.order; - const priceStr = o.price ? `$${o.price.toFixed(8)}` : 'MARKET'; - - let warningsStr = ''; - if (result.data.riskWarnings && result.data.riskWarnings.length > 0) { - warningsStr = `\n\nWarnings:\n${result.data.riskWarnings.map((w) => ` - ${w}`).join('\n')}`; - } - - const formattedOutput = ` -Order Created Successfully -${'='.repeat(35)} -Order ID: ${o.id} -Symbol: ${o.symbol} -Side: ${o.side.toUpperCase()} -Type: ${o.type.toUpperCase()} -Price: ${priceStr} -Amount: ${o.amount.toFixed(8)} -Filled: ${o.filled.toFixed(8)} -Status: ${o.status} -Created: ${new Date(o.createdAt).toISOString()}${warningsStr} -`.trim(); - - return { - content: [{ type: 'text', text: formattedOutput }], - }; - } - - const errorPrefix = result.riskCheckFailed ? 'Risk Check Failed: ' : 'Error: '; - return { - content: [{ type: 'text', text: `${errorPrefix}${result.error}` }], - }; -} - -// ========================================== -// binance_cancel_order -// ========================================== - -/** - * Tool: binance_cancel_order - * Cancel a pending order - */ -export const binanceCancelOrderSchema = { - name: 'binance_cancel_order', - description: 'Cancel a pending order by order ID and symbol', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading pair symbol (e.g., BTCUSDT)', - }, - orderId: { - type: 'string', - description: 'Order ID to cancel', - }, - }, - required: ['symbol', 'orderId'] as string[], - }, - riskLevel: 'MEDIUM', -}; - -export const BinanceCancelOrderInputSchema = z.object({ - symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()), - orderId: z.string().min(1), -}); - -export type BinanceCancelOrderInput = z.infer; - -export interface BinanceCancelOrderResult { - success: boolean; - data?: { - cancelledOrder: BinanceOrder; - }; - error?: string; -} - -export async function binance_cancel_order( - params: BinanceCancelOrderInput -): Promise { - try { - const client = getBinanceClient(); - - if (!client.isConfigured()) { - return { - success: false, - error: 'Binance API keys are not configured', - }; - } - - const result = await client.cancelOrder(params.orderId, params.symbol); - - if (result.success && result.order) { - logger.info('Order cancelled successfully', { - orderId: params.orderId, - symbol: params.symbol, - }); - - return { - success: true, - data: { - cancelledOrder: result.order, - }, - }; - } - - return { - success: false, - error: result.error || 'Failed to cancel order', - }; - } catch (error) { - logger.error('Order cancellation failed', { error, params }); - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleBinanceCancelOrder( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = BinanceCancelOrderInputSchema.parse(params); - const result = await binance_cancel_order(validatedParams); - - if (result.success && result.data) { - const o = result.data.cancelledOrder; - - const formattedOutput = ` -Order Cancelled Successfully -${'='.repeat(35)} -Order ID: ${o.id} -Symbol: ${o.symbol} -Side: ${o.side.toUpperCase()} -Type: ${o.type.toUpperCase()} -Original Amount: ${o.amount.toFixed(8)} -Filled Before Cancel: ${o.filled.toFixed(8)} -Status: ${o.status} -`.trim(); - - return { - content: [{ type: 'text', text: formattedOutput }], - }; - } - - return { - content: [{ type: 'text', text: `Error: ${result.error}` }], - }; -} diff --git a/apps/mcp-binance-connector/src/utils/logger.ts b/apps/mcp-binance-connector/src/utils/logger.ts deleted file mode 100644 index 30f0436..0000000 --- a/apps/mcp-binance-connector/src/utils/logger.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Logger Utility - * - * Winston-based logging for the MCP Binance Connector. - * - * @version 1.0.0 - * @author Trading Platform Trading Platform - */ - -import winston from 'winston'; -import { serverConfig } from '../config'; - -const { combine, timestamp, printf, colorize, errors } = winston.format; - -// Custom log format -const logFormat = printf(({ level, message, timestamp, ...metadata }) => { - let msg = `${timestamp} [${level}]: ${message}`; - - if (Object.keys(metadata).length > 0) { - msg += ` ${JSON.stringify(metadata)}`; - } - - return msg; -}); - -// Create logger instance -export const logger = winston.createLogger({ - level: serverConfig.logLevel, - format: combine( - errors({ stack: true }), - timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - logFormat - ), - defaultMeta: { service: 'mcp-binance-connector' }, - transports: [ - // Console transport - new winston.transports.Console({ - format: combine( - colorize(), - timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - logFormat - ), - }), - ], -}); - -// Add file transport in production -if (serverConfig.nodeEnv === 'production') { - logger.add( - new winston.transports.File({ - filename: process.env.LOG_FILE || 'logs/mcp-binance.log', - maxsize: 10 * 1024 * 1024, // 10MB - maxFiles: 5, - }) - ); - - logger.add( - new winston.transports.File({ - filename: 'logs/mcp-binance-error.log', - level: 'error', - maxsize: 10 * 1024 * 1024, - maxFiles: 5, - }) - ); -} - -export default logger; diff --git a/apps/mcp-binance-connector/tsconfig.json b/apps/mcp-binance-connector/tsconfig.json deleted file mode 100644 index ad10886..0000000 --- a/apps/mcp-binance-connector/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "commonjs", - "lib": ["ES2022"], - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "tests"] -} diff --git a/mcp-investment b/apps/mcp-investment similarity index 100% rename from mcp-investment rename to apps/mcp-investment diff --git a/mcp-mt4-connector b/apps/mcp-mt4-connector similarity index 100% rename from mcp-mt4-connector rename to apps/mcp-mt4-connector diff --git a/apps/mcp-mt4-connector/.env.example b/apps/mcp-mt4-connector/.env.example deleted file mode 100644 index fc845db..0000000 --- a/apps/mcp-mt4-connector/.env.example +++ /dev/null @@ -1,31 +0,0 @@ -# MCP MT4 Connector Configuration -# Copy this file to .env and configure values - -# ========================================== -# Server Configuration -# ========================================== -PORT=3605 -NODE_ENV=development - -# ========================================== -# MT4 Gateway Connection -# ========================================== -# Host where mt4-gateway is running -MT4_GATEWAY_HOST=localhost -# Port of the mt4-gateway service -MT4_GATEWAY_PORT=8081 -# Authentication token for mt4-gateway -MT4_GATEWAY_AUTH_TOKEN=your-secret-token-here - -# ========================================== -# Request Configuration -# ========================================== -# Timeout for requests to MT4 Gateway (ms) -REQUEST_TIMEOUT=10000 -# Maximum retries for failed requests -MAX_RETRIES=3 - -# ========================================== -# Logging -# ========================================== -LOG_LEVEL=info diff --git a/apps/mcp-mt4-connector/.gitignore b/apps/mcp-mt4-connector/.gitignore deleted file mode 100644 index 63cf669..0000000 --- a/apps/mcp-mt4-connector/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Dependencies -node_modules/ - -# Build output -dist/ - -# Environment files -.env -.env.local -.env.*.local - -# IDE -.idea/ -.vscode/ -*.swp -*.swo - -# OS -.DS_Store -Thumbs.db - -# Logs -*.log -logs/ - -# Test coverage -coverage/ - -# Temporary files -tmp/ -temp/ diff --git a/apps/mcp-mt4-connector/README.md b/apps/mcp-mt4-connector/README.md deleted file mode 100644 index efb5b8a..0000000 --- a/apps/mcp-mt4-connector/README.md +++ /dev/null @@ -1,277 +0,0 @@ -# MCP MT4 Connector - -**Version:** 0.1.0 -**Date:** 2026-01-04 -**System:** Trading Platform + NEXUS v3.4 + SIMCO - ---- - -## Description - -MCP Server that exposes MetaTrader 4 (MT4) trading capabilities as tools for AI agents. This service enables AI agents to: -- Query account information -- Monitor open positions -- Execute trades (BUY/SELL) -- Manage positions (modify SL/TP, close) -- Get real-time price quotes - ---- - -## Installation - -```bash -# Navigate to the project -cd /home/isem/workspace-v1/projects/trading-platform/apps/mcp-mt4-connector - -# Install dependencies -npm install - -# Configure environment -cp .env.example .env -# Edit .env with your MT4 Gateway credentials -``` - ---- - -## Configuration - -### Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `PORT` | MCP Server port | 3605 | -| `MT4_GATEWAY_HOST` | MT4 Gateway hostname | localhost | -| `MT4_GATEWAY_PORT` | MT4 Gateway port | 8081 | -| `MT4_GATEWAY_AUTH_TOKEN` | Authentication token | secret | -| `REQUEST_TIMEOUT` | Request timeout (ms) | 10000 | -| `LOG_LEVEL` | Logging level | info | - -### Example .env -```env -PORT=3605 -MT4_GATEWAY_HOST=localhost -MT4_GATEWAY_PORT=8081 -MT4_GATEWAY_AUTH_TOKEN=your-secure-token -REQUEST_TIMEOUT=10000 -LOG_LEVEL=info -``` - ---- - -## Usage - -### Start Server - -```bash -# Development (with hot reload) -npm run dev - -# Production -npm run build -npm start -``` - -### Health Check - -```bash -curl http://localhost:3605/health -``` - -### List Available Tools - -```bash -curl http://localhost:3605/tools -``` - -### Execute a Tool - -```bash -# Get account info -curl -X POST http://localhost:3605/tools/mt4_get_account \ - -H "Content-Type: application/json" \ - -d '{"parameters": {}}' - -# Get price quote -curl -X POST http://localhost:3605/tools/mt4_get_quote \ - -H "Content-Type: application/json" \ - -d '{"parameters": {"symbol": "XAUUSD"}}' - -# Execute trade -curl -X POST http://localhost:3605/tools/mt4_execute_trade \ - -H "Content-Type: application/json" \ - -d '{"parameters": {"symbol": "XAUUSD", "action": "buy", "lots": 0.1}}' -``` - ---- - -## MCP Tools Available - -| Tool | Description | Risk | -|------|-------------|------| -| `mt4_get_account` | Get account balance, equity, margin | Low | -| `mt4_get_positions` | List open positions | Low | -| `mt4_get_quote` | Get current bid/ask price | Low | -| `mt4_execute_trade` | Execute BUY/SELL order | HIGH | -| `mt4_close_position` | Close a position | HIGH | -| `mt4_modify_position` | Modify SL/TP | Medium | - ---- - -## Project Structure - -``` -mcp-mt4-connector/ -├── README.md # This file -├── package.json # Dependencies -├── tsconfig.json # TypeScript configuration -├── .env.example # Environment template -├── .gitignore # Git ignore rules -├── docs/ -│ ├── ARCHITECTURE.md # Architecture documentation -│ └── MCP-TOOLS-SPEC.md # Detailed tool specifications -└── src/ - ├── index.ts # Server entry point - ├── tools/ - │ ├── index.ts # Tool exports - │ ├── account.ts # mt4_get_account - │ ├── positions.ts # mt4_get_positions, mt4_close_position - │ ├── trading.ts # mt4_execute_trade, mt4_modify_position - │ └── quotes.ts # mt4_get_quote - └── services/ - └── mt4-client.ts # MT4 Gateway HTTP client -``` - ---- - -## Development - -### Build - -```bash -npm run build -``` - -### Type Check - -```bash -npm run typecheck -``` - -### Lint - -```bash -npm run lint -npm run lint:fix -``` - -### Test - -```bash -npm run test -npm run test:coverage -``` - ---- - -## Integration with Claude - -### MCP Configuration - -Add to your Claude/MCP configuration: - -```json -{ - "mcpServers": { - "mt4": { - "url": "http://localhost:3605", - "transport": "http" - } - } -} -``` - -### Example Agent Prompts - -``` -"Check my MT4 account balance" -→ Uses mt4_get_account - -"What's the current gold price?" -→ Uses mt4_get_quote({ symbol: "XAUUSD" }) - -"Buy 0.1 lots of XAUUSD with stop loss at 2640" -→ Uses mt4_execute_trade({ symbol: "XAUUSD", action: "buy", lots: 0.1, stopLoss: 2640 }) - -"Close my profitable gold positions" -→ Uses mt4_get_positions({ symbol: "XAUUSD" }) + mt4_close_position for each -``` - ---- - -## Dependencies - -### Runtime -- `express` - HTTP server -- `axios` - HTTP client -- `zod` - Input validation -- `dotenv` - Environment configuration -- `@modelcontextprotocol/sdk` - MCP protocol - -### Development -- `typescript` - Type safety -- `ts-node-dev` - Development server -- `jest` - Testing framework -- `eslint` - Code linting - ---- - -## Prerequisites - -1. **MT4 Gateway** running on configured host:port -2. **MT4 Terminal** connected with EA Bridge active -3. **Node.js** >= 18.0.0 - ---- - -## Troubleshooting - -### Cannot connect to MT4 Gateway -```bash -# Check if mt4-gateway is running -curl http://localhost:8081/status - -# Verify environment variables -cat .env | grep MT4 -``` - -### Tool execution fails -```bash -# Check health endpoint for dependency status -curl http://localhost:3605/health - -# Check server logs -npm run dev # Logs will show in console -``` - -### Invalid parameters error -```bash -# Verify tool schema -curl http://localhost:3605/tools/mt4_execute_trade - -# Check parameter names match schema -``` - ---- - -## References - -- [MCP Protocol](https://modelcontextprotocol.io) -- MT4 Gateway: `apps/mt4-gateway/` -- SIMCO-MCP: `orchestration/directivas/simco/SIMCO-MCP.md` -- Architecture: `docs/ARCHITECTURE.md` -- Tool Specs: `docs/MCP-TOOLS-SPEC.md` - ---- - -**Maintained by:** @PERFIL_MCP_DEVELOPER -**Project:** Trading Platform diff --git a/apps/mcp-mt4-connector/docs/ARCHITECTURE.md b/apps/mcp-mt4-connector/docs/ARCHITECTURE.md deleted file mode 100644 index 5589605..0000000 --- a/apps/mcp-mt4-connector/docs/ARCHITECTURE.md +++ /dev/null @@ -1,272 +0,0 @@ -# MCP MT4 Connector - Architecture - -**Version:** 0.1.0 -**Date:** 2026-01-04 -**System:** Trading Platform - ---- - -## Overview - -The MCP MT4 Connector is a Model Context Protocol (MCP) server that exposes MetaTrader 4 trading capabilities as tools that AI agents can use. It acts as a bridge between MCP-compatible AI systems (like Claude) and the MT4 trading terminal. - ---- - -## Architecture Diagram - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ AI Agent (Claude) │ -│ │ -│ "Execute a buy order for 0.1 lots of XAUUSD with SL at 2640" │ -└─────────────────────────────────────┬───────────────────────────────────┘ - │ MCP Protocol - ▼ -┌─────────────────────────────────────────────────────────────────────────┐ -│ MCP MT4 Connector (Port 3605) │ -│ │ -│ ┌─────────────────────────────────────────────────────────────────┐ │ -│ │ Express Server │ │ -│ │ │ │ -│ │ /health - Health check endpoint │ │ -│ │ /tools - List available tools │ │ -│ │ /tools/:name - Execute specific tool │ │ -│ │ /mcp/* - MCP protocol endpoints │ │ -│ └─────────────────────────────────────────────────────────────────┘ │ -│ │ │ -│ ┌─────────────────────────────────────────────────────────────────┐ │ -│ │ Tool Handlers │ │ -│ │ │ │ -│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ │ -│ │ │ account.ts │ │positions.ts │ │ trading.ts │ │ quotes.ts │ │ │ -│ │ └─────────────┘ └─────────────┘ └─────────────┘ └───────────┘ │ │ -│ └─────────────────────────────────────────────────────────────────┘ │ -│ │ │ -│ ┌─────────────────────────────────────────────────────────────────┐ │ -│ │ MT4 Client Service │ │ -│ │ │ │ -│ │ - HTTP client wrapper for mt4-gateway │ │ -│ │ - Request/response handling │ │ -│ │ - Error management │ │ -│ └─────────────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────┬───────────────────────────────────┘ - │ HTTP/REST - ▼ -┌─────────────────────────────────────────────────────────────────────────┐ -│ MT4 Gateway (Port 8081) │ -│ │ -│ Python service that communicates with MT4 EA Bridge │ -└─────────────────────────────────────┬───────────────────────────────────┘ - │ Local Socket/HTTP - ▼ -┌─────────────────────────────────────────────────────────────────────────┐ -│ MT4 Terminal + EA Bridge │ -│ │ -│ Windows MT4 with Expert Advisor running │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - ---- - -## Component Details - -### 1. Express Server (`src/index.ts`) - -The main entry point that: -- Hosts the MCP server on port 3605 -- Provides REST endpoints for tool execution -- Implements MCP protocol endpoints -- Handles health checks and service discovery - -**Endpoints:** -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/health` | GET | Health check with MT4 connection status | -| `/tools` | GET | List all available MCP tools | -| `/tools/:name` | GET | Get specific tool schema | -| `/tools/:name` | POST | Execute tool with parameters | -| `/mcp/initialize` | POST | MCP initialization handshake | -| `/mcp/tools/list` | POST | MCP tool listing | -| `/mcp/tools/call` | POST | MCP tool execution | - -### 2. Tool Handlers (`src/tools/`) - -Individual tool implementations following the MCP tool pattern: - -| File | Tools | Description | -|------|-------|-------------| -| `account.ts` | `mt4_get_account` | Account information retrieval | -| `positions.ts` | `mt4_get_positions`, `mt4_close_position` | Position management | -| `trading.ts` | `mt4_execute_trade`, `mt4_modify_position` | Trade execution | -| `quotes.ts` | `mt4_get_quote` | Price data retrieval | - -Each tool handler: -- Defines Zod validation schemas -- Implements the core logic -- Formats responses for MCP protocol -- Handles errors gracefully - -### 3. MT4 Client Service (`src/services/mt4-client.ts`) - -HTTP client wrapper that: -- Manages connection to mt4-gateway -- Handles authentication (Bearer token) -- Provides typed interfaces for all operations -- Manages request timeouts and retries - ---- - -## Data Flow - -### Example: Execute Trade - -``` -1. Agent Request - POST /mcp/tools/call - { - "name": "mt4_execute_trade", - "arguments": { - "symbol": "XAUUSD", - "action": "buy", - "lots": 0.1, - "stopLoss": 2640, - "takeProfit": 2680 - } - } - -2. Tool Handler (trading.ts) - - Validates input with Zod schema - - Checks MT4 connection status - - Validates SL/TP logic - - Calls MT4Client.executeTrade() - -3. MT4 Client Service - - Formats request payload - - Sends HTTP POST to mt4-gateway - - Receives and parses response - -4. MT4 Gateway - - Forwards to EA Bridge - - EA executes trade on MT4 - - Returns result - -5. Response to Agent - { - "content": [{ - "type": "text", - "text": "Trade Executed Successfully\n..." - }] - } -``` - ---- - -## Configuration - -### Environment Variables - -| Variable | Default | Description | -|----------|---------|-------------| -| `PORT` | 3605 | MCP server port | -| `MT4_GATEWAY_HOST` | localhost | MT4 Gateway host | -| `MT4_GATEWAY_PORT` | 8081 | MT4 Gateway port | -| `MT4_GATEWAY_AUTH_TOKEN` | secret | Authentication token | -| `REQUEST_TIMEOUT` | 10000 | Request timeout (ms) | -| `LOG_LEVEL` | info | Logging level | - ---- - -## Error Handling - -### Error Types - -1. **Connection Errors** - - MT4 Gateway unreachable - - MT4 Terminal disconnected - -2. **Validation Errors** - - Invalid parameters (Zod) - - Invalid SL/TP configuration - -3. **Trading Errors** - - Insufficient margin - - Market closed - - Invalid symbol - -### Error Response Format - -```json -{ - "success": false, - "error": "Error message description" -} -``` - ---- - -## Security Considerations - -1. **Authentication** - - Bearer token for mt4-gateway communication - - No external network exposure by default - -2. **Validation** - - All inputs validated with Zod schemas - - Type-safe throughout the codebase - -3. **Rate Limiting** - - Consider adding rate limiting for production - - Respect MT4 order frequency limits - ---- - -## Dependencies - -| Package | Purpose | -|---------|---------| -| `express` | HTTP server | -| `axios` | HTTP client | -| `zod` | Input validation | -| `dotenv` | Environment configuration | -| `@modelcontextprotocol/sdk` | MCP protocol types | - ---- - -## Deployment - -### Development - -```bash -npm install -cp .env.example .env -# Edit .env with your configuration -npm run dev -``` - -### Production - -```bash -npm run build -npm start -``` - -### Docker (Future) - -```dockerfile -FROM node:20-alpine -WORKDIR /app -COPY package*.json ./ -RUN npm ci --only=production -COPY dist ./dist -EXPOSE 3605 -CMD ["node", "dist/index.js"] -``` - ---- - -## References - -- MCP Protocol: https://modelcontextprotocol.io -- MT4 Bridge Client: `apps/mt4-gateway/src/providers/mt4_bridge_client.py` -- Trading Platform: `projects/trading-platform/` -- SIMCO-MCP Directive: `orchestration/directivas/simco/SIMCO-MCP.md` diff --git a/apps/mcp-mt4-connector/docs/MCP-TOOLS-SPEC.md b/apps/mcp-mt4-connector/docs/MCP-TOOLS-SPEC.md deleted file mode 100644 index 0ca1830..0000000 --- a/apps/mcp-mt4-connector/docs/MCP-TOOLS-SPEC.md +++ /dev/null @@ -1,428 +0,0 @@ -# MCP MT4 Connector - Tools Specification - -**Version:** 0.1.0 -**Date:** 2026-01-04 -**Total Tools:** 6 - ---- - -## Tool Overview - -| Tool Name | Description | Risk Level | -|-----------|-------------|------------| -| `mt4_get_account` | Get account information | Low | -| `mt4_get_positions` | List open positions | Low | -| `mt4_get_quote` | Get current price quote | Low | -| `mt4_execute_trade` | Execute market order | HIGH | -| `mt4_close_position` | Close a position | HIGH | -| `mt4_modify_position` | Modify SL/TP | Medium | - ---- - -## mt4_get_account - -### Description -Retrieves comprehensive account information from the connected MT4 terminal including balance, equity, margin, leverage, and broker details. - -### Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| - | - | - | No parameters required | - -### Return Value -```json -{ - "success": true, - "data": { - "balance": 10000.00, - "equity": 10250.50, - "margin": 500.00, - "freeMargin": 9750.50, - "marginLevel": 2050.10, - "profit": 250.50, - "currency": "USD", - "leverage": 100, - "name": "Demo Account", - "server": "ICMarkets-Demo", - "company": "IC Markets" - } -} -``` - -### Example Usage -```typescript -// Get account info -const result = await mt4_get_account({}); - -// Response content: -// MT4 Account Information -// ======================= -// Account Name: Demo Account -// Server: ICMarkets-Demo -// Broker: IC Markets -// Leverage: 1:100 -// -// Financial Summary -// ----------------- -// Balance: 10000.00 USD -// Equity: 10250.50 USD -// Profit/Loss: +250.50 USD -``` - -### Errors -| Code | Message | Solution | -|------|---------|----------| -| - | MT4 terminal is not connected | Check MT4 Gateway connection | - ---- - -## mt4_get_positions - -### Description -Lists all currently open trading positions from the MT4 terminal. Can optionally filter by symbol. - -### Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| `symbol` | string | No | Filter positions by symbol (e.g., XAUUSD) | - -### Return Value -```json -{ - "success": true, - "data": { - "positions": [ - { - "ticket": 123456, - "symbol": "XAUUSD", - "type": "buy", - "lots": 0.10, - "openPrice": 2650.50, - "currentPrice": 2655.00, - "stopLoss": 2640.00, - "takeProfit": 2680.00, - "profit": 45.00, - "swap": -1.20, - "openTime": "2026-01-04T10:30:00Z", - "magic": 12345, - "comment": "AI Signal" - } - ], - "totalProfit": 45.00, - "count": 1 - } -} -``` - -### Example Usage -```typescript -// Get all positions -const result = await mt4_get_positions({}); - -// Get only XAUUSD positions -const goldPositions = await mt4_get_positions({ symbol: "XAUUSD" }); -``` - -### Errors -| Code | Message | Solution | -|------|---------|----------| -| - | MT4 terminal is not connected | Check MT4 Gateway connection | - ---- - -## mt4_get_quote - -### Description -Retrieves the current bid/ask prices for a trading symbol. Also calculates the spread in points/pips. - -### Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| `symbol` | string | Yes | Trading symbol (e.g., XAUUSD, EURUSD) | - -### Return Value -```json -{ - "success": true, - "data": { - "symbol": "XAUUSD", - "bid": 2650.50, - "ask": 2650.80, - "spread": 0.30, - "timestamp": "2026-01-04T12:00:00.000Z" - } -} -``` - -### Example Usage -```typescript -// Get gold price -const quote = await mt4_get_quote({ symbol: "XAUUSD" }); - -// Response content: -// Price Quote: XAUUSD -// ========================= -// Bid: 2650.50 -// Ask: 2650.80 -// Spread: 0.30 (3.0 pips) -// Time: 2026-01-04T12:00:00.000Z -``` - -### Errors -| Code | Message | Solution | -|------|---------|----------| -| - | No quote data available for {symbol} | Verify symbol is available on broker | - ---- - -## mt4_execute_trade - -### Description -Opens a new trading position with a market order. Supports BUY and SELL orders with optional stop loss and take profit levels. - -### Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| `symbol` | string | Yes | Trading symbol (e.g., XAUUSD) | -| `action` | string | Yes | Trade direction: "buy" or "sell" | -| `lots` | number | Yes | Volume in lots (e.g., 0.01, 0.1, 1.0) | -| `stopLoss` | number | No | Stop loss price level | -| `takeProfit` | number | No | Take profit price level | -| `slippage` | number | No | Maximum slippage in points (default: 3) | -| `magic` | number | No | Magic number for EA identification (default: 12345) | -| `comment` | string | No | Order comment (max 31 chars) | - -### Return Value -```json -{ - "success": true, - "data": { - "success": true, - "ticket": 123456, - "message": "Order placed successfully", - "symbol": "XAUUSD", - "action": "buy", - "lots": 0.1 - } -} -``` - -### Example Usage -```typescript -// Simple buy order -const result = await mt4_execute_trade({ - symbol: "XAUUSD", - action: "buy", - lots: 0.1 -}); - -// Buy with risk management -const result = await mt4_execute_trade({ - symbol: "XAUUSD", - action: "buy", - lots: 0.1, - stopLoss: 2640.00, - takeProfit: 2680.00, - comment: "AI Signal - Gold Long" -}); - -// Sell order -const result = await mt4_execute_trade({ - symbol: "EURUSD", - action: "sell", - lots: 0.5, - stopLoss: 1.1050, - takeProfit: 1.0900 -}); -``` - -### Validation Rules -- For BUY orders: stopLoss must be below takeProfit -- For SELL orders: stopLoss must be above takeProfit -- Lots must be positive and reasonable (max 100) - -### Errors -| Code | Message | Solution | -|------|---------|----------| -| - | For BUY orders, stop loss must be below take profit | Fix SL/TP levels | -| - | For SELL orders, stop loss must be above take profit | Fix SL/TP levels | -| - | Trade execution failed | Check margin, market hours | - ---- - -## mt4_close_position - -### Description -Closes an open position by ticket number. Can optionally close only a partial volume. - -### Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| `ticket` | number | Yes | Position ticket number to close | -| `lots` | number | No | Partial volume to close (default: close all) | -| `slippage` | number | No | Maximum slippage in points (default: 3) | - -### Return Value -```json -{ - "success": true, - "data": { - "success": true, - "ticket": 123456, - "message": "Position closed" - } -} -``` - -### Example Usage -```typescript -// Close entire position -const result = await mt4_close_position({ - ticket: 123456 -}); - -// Close partial position (0.5 of 1.0 lots) -const result = await mt4_close_position({ - ticket: 123456, - lots: 0.5 -}); -``` - -### Errors -| Code | Message | Solution | -|------|---------|----------| -| - | Position with ticket {x} not found | Verify ticket number | -| - | Requested lots exceeds position size | Reduce lots parameter | - ---- - -## mt4_modify_position - -### Description -Modifies the stop loss and/or take profit levels of an existing open position. - -### Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| `ticket` | number | Yes | Position ticket number to modify | -| `stopLoss` | number | No | New stop loss price level | -| `takeProfit` | number | No | New take profit price level | - -### Return Value -```json -{ - "success": true, - "data": { - "success": true, - "ticket": 123456, - "message": "Position modified successfully" - } -} -``` - -### Example Usage -```typescript -// Set both SL and TP -const result = await mt4_modify_position({ - ticket: 123456, - stopLoss: 2640.00, - takeProfit: 2680.00 -}); - -// Update only take profit (trailing) -const result = await mt4_modify_position({ - ticket: 123456, - takeProfit: 2700.00 -}); - -// Set only stop loss (risk management) -const result = await mt4_modify_position({ - ticket: 123456, - stopLoss: 2650.00 -}); -``` - -### Validation Rules -- At least one of stopLoss or takeProfit must be provided -- For BUY positions: stopLoss must be below takeProfit -- For SELL positions: stopLoss must be above takeProfit - -### Errors -| Code | Message | Solution | -|------|---------|----------| -| - | At least one of stopLoss or takeProfit must be provided | Add SL or TP | -| - | Position with ticket {x} not found | Verify ticket number | -| - | For BUY positions, stop loss must be below take profit | Fix SL/TP levels | - ---- - -## Common Error Responses - -### Connection Error -```json -{ - "success": false, - "error": "MT4 terminal is not connected" -} -``` - -### Validation Error -```json -{ - "success": false, - "error": "Validation error", - "details": [ - { - "path": ["symbol"], - "message": "Required" - } - ] -} -``` - -### Trading Error -```json -{ - "success": false, - "error": "Trade execution failed: Insufficient margin" -} -``` - ---- - -## Usage Examples with AI Agent - -### Scenario 1: Check Account and Open Trade -``` -Agent: "Check my account balance and if equity is above 10000, buy 0.1 lots of XAUUSD" - -1. Call mt4_get_account({}) -2. Parse response, check equity > 10000 -3. Call mt4_execute_trade({ symbol: "XAUUSD", action: "buy", lots: 0.1 }) -``` - -### Scenario 2: Risk Management -``` -Agent: "Set stop loss at 2640 and take profit at 2680 for my gold position" - -1. Call mt4_get_positions({ symbol: "XAUUSD" }) -2. Get ticket number from response -3. Call mt4_modify_position({ ticket: 123456, stopLoss: 2640, takeProfit: 2680 }) -``` - -### Scenario 3: Close Profitable Trades -``` -Agent: "Close all profitable gold positions" - -1. Call mt4_get_positions({ symbol: "XAUUSD" }) -2. Filter positions where profit > 0 -3. For each: Call mt4_close_position({ ticket: ticketNumber }) -``` - ---- - -## Version History - -| Version | Date | Changes | -|---------|------|---------| -| 0.1.0 | 2026-01-04 | Initial release with 6 core tools | diff --git a/apps/mcp-mt4-connector/package-lock.json b/apps/mcp-mt4-connector/package-lock.json deleted file mode 100644 index 465891f..0000000 --- a/apps/mcp-mt4-connector/package-lock.json +++ /dev/null @@ -1,7170 +0,0 @@ -{ - "name": "mcp-mt4-connector", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "mcp-mt4-connector", - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.0", - "axios": "^1.6.0", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "zod": "^3.22.4" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/jest": "^29.5.11", - "@types/node": "^20.10.0", - "@typescript-eslint/eslint-plugin": "^6.13.0", - "@typescript-eslint/parser": "^6.13.0", - "eslint": "^8.54.0", - "jest": "^29.7.0", - "ts-jest": "^29.1.1", - "ts-node-dev": "^2.0.0", - "typescript": "^5.3.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/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/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/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/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "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/@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", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.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": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/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": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "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", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/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/@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": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.7", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.7.tgz", - "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/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": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.1.tgz", - "integrity": "sha512-yO28oVFFC7EBoiKdAn+VqRm+plcfv4v0xp6osG/VsCB0NlPZWi87ajbCZZ8f/RvOFLEu7//rSRmuZZ7lMoe3gQ==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.7", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "jose": "^6.1.1", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "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": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "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" - } - }, - "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": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", - "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "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/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", - "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/strip-json-comments": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", - "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", - "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "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": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "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", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "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", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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 OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "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-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-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/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/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/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/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/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", - "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.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==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", - "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "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.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/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/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/body-parser/node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "dev": true, - "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/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "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-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "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/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001762", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", - "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", - "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true, - "license": "MIT" - }, - "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/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/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/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "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==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "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/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "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": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, - "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/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", - "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "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/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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": ">=0.4.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": ">= 0.8" - } - }, - "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": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "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": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/dynamic-dedupe": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - } - }, - "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/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, - "license": "ISC" - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "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/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "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", - "engines": { - "node": ">= 0.4" - } - }, - "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": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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/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": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "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": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/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": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/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/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": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "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": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "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/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": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "license": "MIT", - "peer": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/express/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/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "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==", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "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-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/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/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "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/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "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/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "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": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/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": "*" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": { - "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/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.3.tgz", - "integrity": "sha512-PmQi306+M/ct/m5s66Hrg+adPnkD5jiO6IjA7WhWw0gSBSo1EcRegwuI1deZ+wd5pzCGynCcn2DprnE4/yEV4w==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "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/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "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/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "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/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "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-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "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/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "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/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "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.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "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/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "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/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", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "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/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": ">=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-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "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/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/router/node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/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/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/test-exclude/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": "*" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-jest": { - "version": "29.4.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", - "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.3", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0 || ^30.0.0", - "@jest/types": "^29.0.0 || ^30.0.0", - "babel-jest": "^29.0.0 || ^30.0.0", - "jest": "^29.0.0 || ^30.0.0", - "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jest-util": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node-dev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", - "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.1", - "dynamic-dedupe": "^0.3.0", - "minimist": "^1.2.6", - "mkdirp": "^1.0.4", - "resolve": "^1.0.0", - "rimraf": "^2.6.1", - "source-map-support": "^0.5.12", - "tree-kill": "^1.2.2", - "ts-node": "^10.4.0", - "tsconfig": "^7.0.0" - }, - "bin": { - "ts-node-dev": "lib/bin.js", - "tsnd": "lib/bin.js" - }, - "engines": { - "node": ">=0.8.0" - }, - "peerDependencies": { - "node-notifier": "*", - "typescript": "*" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/ts-node-dev/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/tsconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", - "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/strip-bom": "^3.0.0", - "@types/strip-json-comments": "0.0.30", - "strip-bom": "^3.0.0", - "strip-json-comments": "^2.0.0" - } - }, - "node_modules/tsconfig/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tsconfig/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "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/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "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/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", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=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" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - } - } -} diff --git a/apps/mcp-mt4-connector/package.json b/apps/mcp-mt4-connector/package.json deleted file mode 100644 index 885c5e6..0000000 --- a/apps/mcp-mt4-connector/package.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "name": "mcp-mt4-connector", - "version": "0.1.0", - "description": "MCP Server for MT4 trading operations via EA Bridge", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "build": "tsc", - "start": "node dist/index.js", - "dev": "ts-node-dev --respawn src/index.ts", - "test": "jest", - "test:watch": "jest --watch", - "test:coverage": "jest --coverage", - "lint": "eslint src/**/*.ts", - "lint:fix": "eslint src/**/*.ts --fix", - "typecheck": "tsc --noEmit", - "health-check": "curl -s http://localhost:${PORT:-3605}/health || echo 'Server not running'" - }, - "keywords": [ - "mcp", - "model-context-protocol", - "anthropic", - "claude", - "mt4", - "metatrader", - "trading", - "forex" - ], - "author": "Trading Platform Trading Platform", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.0", - "axios": "^1.6.0", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "zod": "^3.22.4" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/jest": "^29.5.11", - "@types/node": "^20.10.0", - "@typescript-eslint/eslint-plugin": "^6.13.0", - "@typescript-eslint/parser": "^6.13.0", - "eslint": "^8.54.0", - "jest": "^29.7.0", - "ts-jest": "^29.1.1", - "ts-node-dev": "^2.0.0", - "typescript": "^5.3.0" - }, - "engines": { - "node": ">=18.0.0" - } -} diff --git a/apps/mcp-mt4-connector/src/index.ts b/apps/mcp-mt4-connector/src/index.ts deleted file mode 100644 index cd53b57..0000000 --- a/apps/mcp-mt4-connector/src/index.ts +++ /dev/null @@ -1,291 +0,0 @@ -/** - * MCP Server: MT4 Connector - * - * Exposes MT4 trading capabilities as MCP tools for AI agents. - * Communicates with mt4-gateway service to execute trading operations. - * - * @version 0.1.0 - * @author Trading Platform Trading Platform - */ - -import express, { Request, Response, NextFunction } from 'express'; -import dotenv from 'dotenv'; -import { mcpToolSchemas, toolHandlers } from './tools'; -import { getMT4Client } from './services/mt4-client'; - -// Load environment variables -dotenv.config(); - -const app = express(); -const PORT = process.env.PORT || 3605; -const SERVICE_NAME = 'mcp-mt4-connector'; -const VERSION = '0.1.0'; - -// ========================================== -// Middleware -// ========================================== - -app.use(express.json()); - -// Request logging -app.use((req: Request, _res: Response, next: NextFunction) => { - console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`); - next(); -}); - -// ========================================== -// Health & Status Endpoints -// ========================================== - -/** - * Health check endpoint - */ -app.get('/health', async (_req: Request, res: Response) => { - try { - const client = getMT4Client(); - const mt4Connected = await client.isConnected(); - - res.json({ - status: 'ok', - service: SERVICE_NAME, - version: VERSION, - timestamp: new Date().toISOString(), - dependencies: { - mt4Gateway: mt4Connected ? 'connected' : 'disconnected', - }, - }); - } catch (error) { - res.json({ - status: 'degraded', - service: SERVICE_NAME, - version: VERSION, - timestamp: new Date().toISOString(), - dependencies: { - mt4Gateway: 'error', - }, - error: error instanceof Error ? error.message : 'Unknown error', - }); - } -}); - -/** - * List available MCP tools - */ -app.get('/tools', (_req: Request, res: Response) => { - res.json({ - tools: mcpToolSchemas, - count: mcpToolSchemas.length, - }); -}); - -/** - * Get specific tool schema - */ -app.get('/tools/:toolName', (req: Request, res: Response) => { - const { toolName } = req.params; - const tool = mcpToolSchemas.find(t => t.name === toolName); - - if (!tool) { - res.status(404).json({ - error: `Tool '${toolName}' not found`, - availableTools: mcpToolSchemas.map(t => t.name), - }); - return; - } - - res.json(tool); -}); - -// ========================================== -// MCP Tool Execution Endpoints -// ========================================== - -/** - * Execute an MCP tool - * POST /tools/:toolName - * Body: { parameters: {...} } - */ -app.post('/tools/:toolName', async (req: Request, res: Response) => { - const { toolName } = req.params; - const { parameters = {} } = req.body; - - // Validate tool exists - const handler = toolHandlers[toolName]; - if (!handler) { - res.status(404).json({ - success: false, - error: `Tool '${toolName}' not found`, - availableTools: Object.keys(toolHandlers), - }); - return; - } - - try { - console.log(`[${new Date().toISOString()}] Executing tool: ${toolName}`); - console.log(`Parameters: ${JSON.stringify(parameters)}`); - - const result = await handler(parameters); - - res.json({ - success: true, - tool: toolName, - result, - }); - } catch (error) { - console.error(`[${new Date().toISOString()}] Tool error: ${toolName}`, error); - - // Handle Zod validation errors - if (error && typeof error === 'object' && 'issues' in error) { - res.status(400).json({ - success: false, - error: 'Validation error', - details: (error as { issues: unknown[] }).issues, - }); - return; - } - - res.status(500).json({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - }); - } -}); - -// ========================================== -// MCP Protocol Endpoints (Standard) -// ========================================== - -/** - * MCP Initialize - * Returns server capabilities - */ -app.post('/mcp/initialize', (_req: Request, res: Response) => { - res.json({ - protocolVersion: '2024-11-05', - capabilities: { - tools: {}, - }, - serverInfo: { - name: SERVICE_NAME, - version: VERSION, - }, - }); -}); - -/** - * MCP List Tools - * Returns all available tools in MCP format - */ -app.post('/mcp/tools/list', (_req: Request, res: Response) => { - res.json({ - tools: mcpToolSchemas.map(tool => ({ - name: tool.name, - description: tool.description, - inputSchema: tool.inputSchema, - })), - }); -}); - -/** - * MCP Call Tool - * Execute a tool with parameters - */ -app.post('/mcp/tools/call', async (req: Request, res: Response) => { - const { name, arguments: args = {} } = req.body; - - if (!name) { - res.status(400).json({ - error: { - code: 'invalid_request', - message: 'Tool name is required', - }, - }); - return; - } - - const handler = toolHandlers[name]; - if (!handler) { - res.status(404).json({ - error: { - code: 'unknown_tool', - message: `Tool '${name}' not found`, - }, - }); - return; - } - - try { - const result = await handler(args); - res.json(result); - } catch (error) { - // Handle Zod validation errors - if (error && typeof error === 'object' && 'issues' in error) { - res.status(400).json({ - error: { - code: 'invalid_params', - message: 'Invalid tool parameters', - data: (error as { issues: unknown[] }).issues, - }, - }); - return; - } - - res.status(500).json({ - error: { - code: 'internal_error', - message: error instanceof Error ? error.message : 'Unknown error', - }, - }); - } -}); - -// ========================================== -// Error Handler -// ========================================== - -app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { - console.error(`[${new Date().toISOString()}] Unhandled error:`, err); - res.status(500).json({ - error: 'Internal server error', - message: err.message, - }); -}); - -// ========================================== -// Start Server -// ========================================== - -app.listen(PORT, () => { - console.log(''); - console.log('╔══════════════════════════════════════════════════════════╗'); - console.log('║ MCP MT4 Connector - Trading Platform ║'); - console.log('╠══════════════════════════════════════════════════════════╣'); - console.log(`║ Service: ${SERVICE_NAME.padEnd(45)}║`); - console.log(`║ Version: ${VERSION.padEnd(45)}║`); - console.log(`║ Port: ${String(PORT).padEnd(48)}║`); - console.log('╠══════════════════════════════════════════════════════════╣'); - console.log('║ Endpoints: ║'); - console.log(`║ - Health: http://localhost:${PORT}/health`.padEnd(63) + '║'); - console.log(`║ - Tools: http://localhost:${PORT}/tools`.padEnd(63) + '║'); - console.log('╠══════════════════════════════════════════════════════════╣'); - console.log('║ MCP Tools Available: ║'); - mcpToolSchemas.forEach(tool => { - console.log(`║ - ${tool.name.padEnd(54)}║`); - }); - console.log('╚══════════════════════════════════════════════════════════╝'); - console.log(''); -}); - -// ========================================== -// Graceful Shutdown -// ========================================== - -process.on('SIGTERM', () => { - console.log('Received SIGTERM, shutting down gracefully...'); - process.exit(0); -}); - -process.on('SIGINT', () => { - console.log('Received SIGINT, shutting down gracefully...'); - process.exit(0); -}); diff --git a/apps/mcp-mt4-connector/src/services/mt4-client.ts b/apps/mcp-mt4-connector/src/services/mt4-client.ts deleted file mode 100644 index 0ef06ea..0000000 --- a/apps/mcp-mt4-connector/src/services/mt4-client.ts +++ /dev/null @@ -1,375 +0,0 @@ -/** - * MT4 Client Service - * - * HTTP client wrapper for communicating with mt4-gateway. - * This service mirrors the functionality of mt4_bridge_client.py - * but is written in TypeScript for the MCP Server. - */ - -import axios, { AxiosInstance, AxiosError } from 'axios'; - -// ========================================== -// Types -// ========================================== - -export interface MT4AccountInfo { - balance: number; - equity: number; - margin: number; - freeMargin: number; - marginLevel: number | null; - profit: number; - currency: string; - leverage: number; - name: string; - server: string; - company: string; -} - -export interface MT4Position { - ticket: number; - symbol: string; - type: 'buy' | 'sell'; - lots: number; - openPrice: number; - currentPrice: number; - stopLoss: number | null; - takeProfit: number | null; - profit: number; - swap: number; - openTime: string; - magic: number; - comment: string; -} - -export interface MT4Tick { - symbol: string; - bid: number; - ask: number; - timestamp: string; - spread: number; -} - -export interface TradeResult { - success: boolean; - ticket?: number; - message: string; - errorCode?: number; -} - -export interface TradeRequest { - action: 'buy' | 'sell'; - symbol: string; - lots: number; - stopLoss?: number; - takeProfit?: number; - price?: number; - slippage?: number; - magic?: number; - comment?: string; -} - -export interface ClosePositionRequest { - ticket: number; - lots?: number; - slippage?: number; -} - -export interface ModifyPositionRequest { - ticket: number; - stopLoss?: number; - takeProfit?: number; -} - -export interface MT4ClientConfig { - host: string; - port: number; - authToken: string; - timeout?: number; -} - -// ========================================== -// MT4 Client Class -// ========================================== - -export class MT4Client { - private client: AxiosInstance; - private baseUrl: string; - - constructor(config: MT4ClientConfig) { - this.baseUrl = `http://${config.host}:${config.port}`; - - this.client = axios.create({ - baseURL: this.baseUrl, - timeout: config.timeout || 10000, - headers: { - 'Authorization': `Bearer ${config.authToken}`, - 'Content-Type': 'application/json', - }, - }); - } - - /** - * Check if the MT4 terminal is connected - */ - async isConnected(): Promise { - try { - const response = await this.client.get('/status'); - return response.data?.connected ?? false; - } catch { - return false; - } - } - - /** - * Get MT4 account information - */ - async getAccountInfo(): Promise { - try { - const response = await this.client.get('/account'); - const data = response.data; - - return { - balance: data.balance ?? 0, - equity: data.equity ?? 0, - margin: data.margin ?? 0, - freeMargin: data.freeMargin ?? 0, - marginLevel: data.marginLevel ?? null, - profit: data.profit ?? 0, - currency: data.currency ?? 'USD', - leverage: data.leverage ?? 100, - name: data.name ?? '', - server: data.server ?? '', - company: data.company ?? '', - }; - } catch (error) { - throw this.handleError(error, 'Failed to get account info'); - } - } - - /** - * Get current tick (quote) for a symbol - */ - async getTick(symbol: string): Promise { - try { - const response = await this.client.get(`/tick/${symbol}`); - const data = response.data; - - const bid = data.bid ?? 0; - const ask = data.ask ?? 0; - - return { - symbol, - bid, - ask, - timestamp: data.time ?? new Date().toISOString(), - spread: Math.round((ask - bid) * 100000) / 100000, - }; - } catch (error) { - throw this.handleError(error, `Failed to get tick for ${symbol}`); - } - } - - /** - * Get all open positions - */ - async getPositions(): Promise { - try { - const response = await this.client.get('/positions'); - const data = response.data; - - if (!Array.isArray(data)) { - return []; - } - - return data.map((p: Record) => ({ - ticket: (p.ticket as number) ?? 0, - symbol: (p.symbol as string) ?? '', - type: (p.type as 'buy' | 'sell') ?? 'buy', - lots: (p.lots as number) ?? 0, - openPrice: (p.openPrice as number) ?? 0, - currentPrice: (p.currentPrice as number) ?? 0, - stopLoss: (p.stopLoss as number | null) ?? null, - takeProfit: (p.takeProfit as number | null) ?? null, - profit: (p.profit as number) ?? 0, - swap: (p.swap as number) ?? 0, - openTime: (p.openTime as string) ?? new Date().toISOString(), - magic: (p.magic as number) ?? 0, - comment: (p.comment as string) ?? '', - })); - } catch (error) { - throw this.handleError(error, 'Failed to get positions'); - } - } - - /** - * Get a specific position by ticket - */ - async getPosition(ticket: number): Promise { - const positions = await this.getPositions(); - return positions.find(p => p.ticket === ticket) ?? null; - } - - /** - * Execute a trade (buy or sell) - */ - async executeTrade(request: TradeRequest): Promise { - try { - const payload: Record = { - action: request.action, - symbol: request.symbol, - lots: request.lots, - slippage: request.slippage ?? 3, - magic: request.magic ?? 12345, - comment: request.comment ?? 'MCP-MT4', - }; - - if (request.stopLoss !== undefined) { - payload.stopLoss = request.stopLoss; - } - if (request.takeProfit !== undefined) { - payload.takeProfit = request.takeProfit; - } - if (request.price !== undefined) { - payload.price = request.price; - } - - const response = await this.client.post('/trade', payload); - const data = response.data; - - return { - success: data.success ?? false, - ticket: data.ticket, - message: data.message ?? '', - errorCode: data.errorCode, - }; - } catch (error) { - return { - success: false, - message: this.getErrorMessage(error), - }; - } - } - - /** - * Close a position - */ - async closePosition(request: ClosePositionRequest): Promise { - try { - const payload: Record = { - action: 'close', - ticket: request.ticket, - slippage: request.slippage ?? 3, - }; - - if (request.lots !== undefined) { - payload.lots = request.lots; - } - - const response = await this.client.post('/trade', payload); - const data = response.data; - - return { - success: data.success ?? false, - ticket: request.ticket, - message: data.message ?? '', - errorCode: data.errorCode, - }; - } catch (error) { - return { - success: false, - ticket: request.ticket, - message: this.getErrorMessage(error), - }; - } - } - - /** - * Modify a position (SL/TP) - */ - async modifyPosition(request: ModifyPositionRequest): Promise { - try { - const payload: Record = { - action: 'modify', - ticket: request.ticket, - }; - - if (request.stopLoss !== undefined) { - payload.stopLoss = request.stopLoss; - } - if (request.takeProfit !== undefined) { - payload.takeProfit = request.takeProfit; - } - - const response = await this.client.post('/trade', payload); - const data = response.data; - - return { - success: data.success ?? false, - ticket: request.ticket, - message: data.message ?? '', - errorCode: data.errorCode, - }; - } catch (error) { - return { - success: false, - ticket: request.ticket, - message: this.getErrorMessage(error), - }; - } - } - - /** - * Handle axios errors and convert to meaningful messages - */ - private handleError(error: unknown, context: string): Error { - const message = this.getErrorMessage(error); - return new Error(`${context}: ${message}`); - } - - /** - * Extract error message from various error types - */ - private getErrorMessage(error: unknown): string { - if (axios.isAxiosError(error)) { - const axiosError = error as AxiosError; - if (axiosError.response) { - return `HTTP ${axiosError.response.status}: ${JSON.stringify(axiosError.response.data)}`; - } - if (axiosError.code === 'ECONNREFUSED') { - return 'Connection refused - MT4 Gateway is not running'; - } - if (axiosError.code === 'ETIMEDOUT') { - return 'Connection timeout - MT4 Gateway is not responding'; - } - return axiosError.message; - } - if (error instanceof Error) { - return error.message; - } - return 'Unknown error'; - } -} - -// ========================================== -// Singleton Instance -// ========================================== - -let clientInstance: MT4Client | null = null; - -export function getMT4Client(): MT4Client { - if (!clientInstance) { - const config: MT4ClientConfig = { - host: process.env.MT4_GATEWAY_HOST || 'localhost', - port: parseInt(process.env.MT4_GATEWAY_PORT || '8081', 10), - authToken: process.env.MT4_GATEWAY_AUTH_TOKEN || 'secret', - timeout: parseInt(process.env.REQUEST_TIMEOUT || '10000', 10), - }; - clientInstance = new MT4Client(config); - } - return clientInstance; -} - -export function resetMT4Client(): void { - clientInstance = null; -} diff --git a/apps/mcp-mt4-connector/src/tools/account.ts b/apps/mcp-mt4-connector/src/tools/account.ts deleted file mode 100644 index b8a22c1..0000000 --- a/apps/mcp-mt4-connector/src/tools/account.ts +++ /dev/null @@ -1,143 +0,0 @@ -/** - * mt4_get_account - Get MT4 account information - * - * @description Retrieves comprehensive account information from the connected MT4 terminal - * including balance, equity, margin, leverage, and broker details. - * - * @returns Account information object with balance, equity, margin details - * - * @example - * const result = await mt4_get_account({}); - * // Returns: - * // { - * // balance: 10000.00, - * // equity: 10250.50, - * // margin: 500.00, - * // freeMargin: 9750.50, - * // marginLevel: 2050.10, - * // profit: 250.50, - * // currency: "USD", - * // leverage: 100, - * // name: "Demo Account", - * // server: "ICMarkets-Demo", - * // company: "IC Markets" - * // } - */ - -import { z } from 'zod'; -import { getMT4Client, MT4AccountInfo } from '../services/mt4-client'; - -// ========================================== -// Schema Definition -// ========================================== - -export const mt4GetAccountSchema = { - name: 'mt4_get_account', - description: 'Get MT4 account information including balance, equity, margin, and broker details', - inputSchema: { - type: 'object' as const, - properties: {}, - required: [] as string[], - }, -}; - -// Input validation schema (no params required) -export const Mt4GetAccountInputSchema = z.object({}); - -export type Mt4GetAccountInput = z.infer; - -// ========================================== -// Tool Implementation -// ========================================== - -export interface Mt4GetAccountResult { - success: boolean; - data?: MT4AccountInfo; - error?: string; -} - -export async function mt4_get_account( - _params: Mt4GetAccountInput -): Promise { - try { - const client = getMT4Client(); - - // Check connection first - const isConnected = await client.isConnected(); - if (!isConnected) { - return { - success: false, - error: 'MT4 terminal is not connected', - }; - } - - // Get account info - const accountInfo = await client.getAccountInfo(); - - return { - success: true, - data: accountInfo, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -// ========================================== -// MCP Tool Handler -// ========================================== - -export async function handleMt4GetAccount( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - // Validate input - const validatedParams = Mt4GetAccountInputSchema.parse(params); - - // Execute tool - const result = await mt4_get_account(validatedParams); - - // Format response for MCP - if (result.success && result.data) { - const formattedOutput = ` -MT4 Account Information -======================= -Account Name: ${result.data.name} -Server: ${result.data.server} -Broker: ${result.data.company} -Leverage: 1:${result.data.leverage} - -Financial Summary ------------------ -Balance: ${result.data.balance.toFixed(2)} ${result.data.currency} -Equity: ${result.data.equity.toFixed(2)} ${result.data.currency} -Profit/Loss: ${result.data.profit >= 0 ? '+' : ''}${result.data.profit.toFixed(2)} ${result.data.currency} - -Margin Details --------------- -Used Margin: ${result.data.margin.toFixed(2)} ${result.data.currency} -Free Margin: ${result.data.freeMargin.toFixed(2)} ${result.data.currency} -Margin Level: ${result.data.marginLevel !== null ? result.data.marginLevel.toFixed(2) + '%' : 'N/A'} -`.trim(); - - return { - content: [ - { - type: 'text', - text: formattedOutput, - }, - ], - }; - } - - return { - content: [ - { - type: 'text', - text: `Error: ${result.error}`, - }, - ], - }; -} diff --git a/apps/mcp-mt4-connector/src/tools/index.ts b/apps/mcp-mt4-connector/src/tools/index.ts deleted file mode 100644 index da0e937..0000000 --- a/apps/mcp-mt4-connector/src/tools/index.ts +++ /dev/null @@ -1,212 +0,0 @@ -/** - * MCP Tools Index - * - * Exports all MT4 MCP tools and their schemas for registration - */ - -// Import handlers for use in toolHandlers map -import { handleMt4GetAccount } from './account'; -import { handleMt4GetPositions, handleMt4ClosePosition } from './positions'; -import { handleMt4ExecuteTrade, handleMt4ModifyPosition } from './trading'; -import { handleMt4GetQuote } from './quotes'; - -// Account tools -export { - mt4GetAccountSchema, - mt4_get_account, - handleMt4GetAccount, - Mt4GetAccountInputSchema, - type Mt4GetAccountInput, - type Mt4GetAccountResult, -} from './account'; - -// Position tools -export { - mt4GetPositionsSchema, - mt4_get_positions, - handleMt4GetPositions, - Mt4GetPositionsInputSchema, - mt4ClosePositionSchema, - mt4_close_position, - handleMt4ClosePosition, - Mt4ClosePositionInputSchema, - type Mt4GetPositionsInput, - type Mt4GetPositionsResult, - type Mt4ClosePositionInput, - type Mt4ClosePositionResult, -} from './positions'; - -// Trading tools -export { - mt4ExecuteTradeSchema, - mt4_execute_trade, - handleMt4ExecuteTrade, - Mt4ExecuteTradeInputSchema, - mt4ModifyPositionSchema, - mt4_modify_position, - handleMt4ModifyPosition, - Mt4ModifyPositionInputSchema, - type Mt4ExecuteTradeInput, - type Mt4ExecuteTradeResult, - type Mt4ModifyPositionInput, - type Mt4ModifyPositionResult, -} from './trading'; - -// Quote tools -export { - mt4GetQuoteSchema, - mt4_get_quote, - handleMt4GetQuote, - Mt4GetQuoteInputSchema, - type Mt4GetQuoteInput, - type Mt4GetQuoteResult, -} from './quotes'; - -// ========================================== -// Tool Registry -// ========================================== - -/** - * All available MCP tools with their schemas - */ -export const mcpToolSchemas = [ - { - name: 'mt4_get_account', - description: 'Get MT4 account information including balance, equity, margin, and broker details', - inputSchema: { - type: 'object' as const, - properties: {}, - required: [] as string[], - }, - }, - { - name: 'mt4_get_positions', - description: 'List all open trading positions from MT4. Optionally filter by symbol.', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Optional: Filter positions by symbol (e.g., XAUUSD, EURUSD)', - }, - }, - required: [] as string[], - }, - }, - { - name: 'mt4_execute_trade', - description: 'Execute a market order (BUY or SELL) on MT4 with optional stop loss and take profit', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading symbol (e.g., XAUUSD, EURUSD, GBPUSD)', - }, - action: { - type: 'string', - enum: ['buy', 'sell'], - description: 'Trade direction: buy or sell', - }, - lots: { - type: 'number', - description: 'Volume in lots (e.g., 0.01, 0.1, 1.0)', - }, - stopLoss: { - type: 'number', - description: 'Optional: Stop loss price level', - }, - takeProfit: { - type: 'number', - description: 'Optional: Take profit price level', - }, - slippage: { - type: 'number', - description: 'Optional: Maximum slippage in points (default: 3)', - }, - magic: { - type: 'number', - description: 'Optional: Magic number for EA identification (default: 12345)', - }, - comment: { - type: 'string', - description: 'Optional: Order comment (max 31 chars)', - }, - }, - required: ['symbol', 'action', 'lots'] as string[], - }, - }, - { - name: 'mt4_close_position', - description: 'Close an open trading position by ticket number. Can close partially.', - inputSchema: { - type: 'object' as const, - properties: { - ticket: { - type: 'number', - description: 'Position ticket number to close', - }, - lots: { - type: 'number', - description: 'Optional: Partial volume to close. If not specified, closes entire position.', - }, - slippage: { - type: 'number', - description: 'Optional: Maximum slippage in points (default: 3)', - }, - }, - required: ['ticket'] as string[], - }, - }, - { - name: 'mt4_modify_position', - description: 'Modify stop loss and/or take profit of an existing position', - inputSchema: { - type: 'object' as const, - properties: { - ticket: { - type: 'number', - description: 'Position ticket number to modify', - }, - stopLoss: { - type: 'number', - description: 'New stop loss price level (optional)', - }, - takeProfit: { - type: 'number', - description: 'New take profit price level (optional)', - }, - }, - required: ['ticket'] as string[], - }, - }, - { - name: 'mt4_get_quote', - description: 'Get current price quote (bid/ask/spread) for a trading symbol', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading symbol to get quote for (e.g., XAUUSD, EURUSD, GBPUSD)', - }, - }, - required: ['symbol'] as string[], - }, - }, -]; - -/** - * Tool handler routing map - */ -export const toolHandlers: Record< - string, - (params: unknown) => Promise<{ content: Array<{ type: string; text: string }> }> -> = { - mt4_get_account: handleMt4GetAccount, - mt4_get_positions: handleMt4GetPositions, - mt4_execute_trade: handleMt4ExecuteTrade, - mt4_close_position: handleMt4ClosePosition, - mt4_modify_position: handleMt4ModifyPosition, - mt4_get_quote: handleMt4GetQuote, -}; diff --git a/apps/mcp-mt4-connector/src/tools/positions.ts b/apps/mcp-mt4-connector/src/tools/positions.ts deleted file mode 100644 index c088568..0000000 --- a/apps/mcp-mt4-connector/src/tools/positions.ts +++ /dev/null @@ -1,315 +0,0 @@ -/** - * MT4 Position Tools - * - * - mt4_get_positions: List all open positions - * - mt4_close_position: Close a specific position - */ - -import { z } from 'zod'; -import { getMT4Client, MT4Position, TradeResult } from '../services/mt4-client'; - -// ========================================== -// mt4_get_positions -// ========================================== - -/** - * mt4_get_positions - List all open positions - * - * @description Retrieves all currently open positions from MT4 terminal. - * Can optionally filter by symbol. - * - * @param symbol - Optional symbol to filter positions (e.g., "XAUUSD") - * @returns Array of open positions with details - * - * @example - * const result = await mt4_get_positions({}); - * // Returns all positions - * - * const result = await mt4_get_positions({ symbol: "XAUUSD" }); - * // Returns only XAUUSD positions - */ - -export const mt4GetPositionsSchema = { - name: 'mt4_get_positions', - description: 'List all open trading positions from MT4. Optionally filter by symbol.', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Optional: Filter positions by symbol (e.g., XAUUSD, EURUSD)', - }, - }, - required: [] as string[], - }, -}; - -export const Mt4GetPositionsInputSchema = z.object({ - symbol: z.string().optional(), -}); - -export type Mt4GetPositionsInput = z.infer; - -export interface Mt4GetPositionsResult { - success: boolean; - data?: { - positions: MT4Position[]; - totalProfit: number; - count: number; - }; - error?: string; -} - -export async function mt4_get_positions( - params: Mt4GetPositionsInput -): Promise { - try { - const client = getMT4Client(); - - // Check connection - const isConnected = await client.isConnected(); - if (!isConnected) { - return { - success: false, - error: 'MT4 terminal is not connected', - }; - } - - // Get all positions - let positions = await client.getPositions(); - - // Filter by symbol if specified - if (params.symbol) { - positions = positions.filter( - p => p.symbol.toUpperCase() === params.symbol!.toUpperCase() - ); - } - - // Calculate total profit - const totalProfit = positions.reduce((sum, p) => sum + p.profit, 0); - - return { - success: true, - data: { - positions, - totalProfit, - count: positions.length, - }, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleMt4GetPositions( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = Mt4GetPositionsInputSchema.parse(params); - const result = await mt4_get_positions(validatedParams); - - if (result.success && result.data) { - if (result.data.count === 0) { - return { - content: [ - { - type: 'text', - text: params && (params as Mt4GetPositionsInput).symbol - ? `No open positions found for ${(params as Mt4GetPositionsInput).symbol}` - : 'No open positions found', - }, - ], - }; - } - - const positionLines = result.data.positions.map(p => { - const direction = p.type.toUpperCase(); - const profitSign = p.profit >= 0 ? '+' : ''; - const slInfo = p.stopLoss !== null ? `SL: ${p.stopLoss}` : 'SL: None'; - const tpInfo = p.takeProfit !== null ? `TP: ${p.takeProfit}` : 'TP: None'; - - return ` -#${p.ticket} | ${p.symbol} | ${direction} ${p.lots} lots - Open: ${p.openPrice} | Current: ${p.currentPrice} - ${slInfo} | ${tpInfo} - P/L: ${profitSign}${p.profit.toFixed(2)} | Swap: ${p.swap.toFixed(2)} - Opened: ${p.openTime} - Magic: ${p.magic} | Comment: ${p.comment || 'None'}`; - }); - - const formattedOutput = ` -Open Positions (${result.data.count}) -${'='.repeat(30)} -${positionLines.join('\n---\n')} - -Total P/L: ${result.data.totalProfit >= 0 ? '+' : ''}${result.data.totalProfit.toFixed(2)} -`.trim(); - - return { - content: [ - { - type: 'text', - text: formattedOutput, - }, - ], - }; - } - - return { - content: [ - { - type: 'text', - text: `Error: ${result.error}`, - }, - ], - }; -} - -// ========================================== -// mt4_close_position -// ========================================== - -/** - * mt4_close_position - Close a trading position - * - * @description Closes an open position by ticket number. - * Can optionally close partial volume. - * - * @param ticket - Position ticket number to close - * @param lots - Optional: Partial volume to close (default: close all) - * @param slippage - Optional: Maximum slippage in points (default: 3) - * @returns Trade result with success status - * - * @example - * // Close entire position - * const result = await mt4_close_position({ ticket: 123456 }); - * - * // Close partial position - * const result = await mt4_close_position({ ticket: 123456, lots: 0.5 }); - */ - -export const mt4ClosePositionSchema = { - name: 'mt4_close_position', - description: 'Close an open trading position by ticket number. Can close partially.', - inputSchema: { - type: 'object' as const, - properties: { - ticket: { - type: 'number', - description: 'Position ticket number to close', - }, - lots: { - type: 'number', - description: 'Optional: Partial volume to close. If not specified, closes entire position.', - }, - slippage: { - type: 'number', - description: 'Optional: Maximum slippage in points (default: 3)', - }, - }, - required: ['ticket'] as string[], - }, -}; - -export const Mt4ClosePositionInputSchema = z.object({ - ticket: z.number().int().positive(), - lots: z.number().positive().optional(), - slippage: z.number().int().min(0).max(100).optional(), -}); - -export type Mt4ClosePositionInput = z.infer; - -export interface Mt4ClosePositionResult { - success: boolean; - data?: TradeResult; - error?: string; -} - -export async function mt4_close_position( - params: Mt4ClosePositionInput -): Promise { - try { - const client = getMT4Client(); - - // Check connection - const isConnected = await client.isConnected(); - if (!isConnected) { - return { - success: false, - error: 'MT4 terminal is not connected', - }; - } - - // Verify position exists - const position = await client.getPosition(params.ticket); - if (!position) { - return { - success: false, - error: `Position with ticket ${params.ticket} not found`, - }; - } - - // Validate lots if specified - if (params.lots !== undefined && params.lots > position.lots) { - return { - success: false, - error: `Requested lots (${params.lots}) exceeds position size (${position.lots})`, - }; - } - - // Close position - const result = await client.closePosition({ - ticket: params.ticket, - lots: params.lots, - slippage: params.slippage, - }); - - return { - success: result.success, - data: result, - error: result.success ? undefined : result.message, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleMt4ClosePosition( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = Mt4ClosePositionInputSchema.parse(params); - const result = await mt4_close_position(validatedParams); - - if (result.success && result.data) { - const formattedOutput = ` -Position Closed Successfully -============================ -Ticket: ${validatedParams.ticket} -${validatedParams.lots ? `Closed Volume: ${validatedParams.lots} lots` : 'Closed: Entire position'} -Message: ${result.data.message || 'Position closed'} -`.trim(); - - return { - content: [ - { - type: 'text', - text: formattedOutput, - }, - ], - }; - } - - return { - content: [ - { - type: 'text', - text: `Error closing position: ${result.error}`, - }, - ], - }; -} diff --git a/apps/mcp-mt4-connector/src/tools/quotes.ts b/apps/mcp-mt4-connector/src/tools/quotes.ts deleted file mode 100644 index c8f5dab..0000000 --- a/apps/mcp-mt4-connector/src/tools/quotes.ts +++ /dev/null @@ -1,193 +0,0 @@ -/** - * mt4_get_quote - Get current price quote for a symbol - * - * @description Retrieves the current bid/ask prices for a trading symbol. - * Also calculates the spread in points. - * - * @param symbol - Trading symbol to get quote for (e.g., "XAUUSD") - * @returns Current bid, ask, spread, and timestamp - * - * @example - * const result = await mt4_get_quote({ symbol: "XAUUSD" }); - * // Returns: - * // { - * // symbol: "XAUUSD", - * // bid: 2650.50, - * // ask: 2650.80, - * // spread: 0.30, - * // timestamp: "2026-01-04T12:00:00.000Z" - * // } - */ - -import { z } from 'zod'; -import { getMT4Client, MT4Tick } from '../services/mt4-client'; - -// ========================================== -// Schema Definition -// ========================================== - -export const mt4GetQuoteSchema = { - name: 'mt4_get_quote', - description: 'Get current price quote (bid/ask/spread) for a trading symbol', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading symbol to get quote for (e.g., XAUUSD, EURUSD, GBPUSD)', - }, - }, - required: ['symbol'] as string[], - }, -}; - -export const Mt4GetQuoteInputSchema = z.object({ - symbol: z.string().min(1).max(20), -}); - -export type Mt4GetQuoteInput = z.infer; - -// ========================================== -// Tool Implementation -// ========================================== - -export interface Mt4GetQuoteResult { - success: boolean; - data?: MT4Tick; - error?: string; -} - -export async function mt4_get_quote( - params: Mt4GetQuoteInput -): Promise { - try { - const client = getMT4Client(); - - // Check connection - const isConnected = await client.isConnected(); - if (!isConnected) { - return { - success: false, - error: 'MT4 terminal is not connected', - }; - } - - // Get tick data - const tick = await client.getTick(params.symbol.toUpperCase()); - - // Validate we got valid data - if (tick.bid === 0 && tick.ask === 0) { - return { - success: false, - error: `No quote data available for ${params.symbol}. Symbol may not be available on this broker.`, - }; - } - - return { - success: true, - data: tick, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -// ========================================== -// MCP Tool Handler -// ========================================== - -export async function handleMt4GetQuote( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = Mt4GetQuoteInputSchema.parse(params); - const result = await mt4_get_quote(validatedParams); - - if (result.success && result.data) { - // Determine decimal places based on symbol - const decimals = getDecimalPlaces(result.data.symbol); - const spreadPips = calculateSpreadPips(result.data.spread, result.data.symbol); - - const formattedOutput = ` -Price Quote: ${result.data.symbol} -${'='.repeat(25)} -Bid: ${result.data.bid.toFixed(decimals)} -Ask: ${result.data.ask.toFixed(decimals)} -Spread: ${result.data.spread.toFixed(decimals)} (${spreadPips.toFixed(1)} pips) -Time: ${result.data.timestamp} -`.trim(); - - return { - content: [ - { - type: 'text', - text: formattedOutput, - }, - ], - }; - } - - return { - content: [ - { - type: 'text', - text: `Error: ${result.error}`, - }, - ], - }; -} - -// ========================================== -// Helper Functions -// ========================================== - -/** - * Determine decimal places based on symbol type - */ -function getDecimalPlaces(symbol: string): number { - const upperSymbol = symbol.toUpperCase(); - - // JPY pairs have 3 decimals, most forex 5 decimals - if (upperSymbol.includes('JPY')) { - return 3; - } - - // Gold and metals typically 2 decimals - if (upperSymbol.startsWith('XAU') || upperSymbol.startsWith('XAG')) { - return 2; - } - - // Indices vary, use 2 as default - if ( - upperSymbol.includes('US30') || - upperSymbol.includes('US500') || - upperSymbol.includes('NAS') - ) { - return 2; - } - - // Default forex pairs - return 5; -} - -/** - * Calculate spread in pips based on symbol - */ -function calculateSpreadPips(spread: number, symbol: string): number { - const upperSymbol = symbol.toUpperCase(); - - // JPY pairs: 1 pip = 0.01 - if (upperSymbol.includes('JPY')) { - return spread * 100; - } - - // Gold: 1 pip = 0.10 - if (upperSymbol.startsWith('XAU')) { - return spread * 10; - } - - // Default forex: 1 pip = 0.0001 - return spread * 10000; -} diff --git a/apps/mcp-mt4-connector/src/tools/trading.ts b/apps/mcp-mt4-connector/src/tools/trading.ts deleted file mode 100644 index 1258d1a..0000000 --- a/apps/mcp-mt4-connector/src/tools/trading.ts +++ /dev/null @@ -1,402 +0,0 @@ -/** - * MT4 Trading Tools - * - * - mt4_execute_trade: Execute BUY/SELL market orders - * - mt4_modify_position: Modify SL/TP of existing positions - */ - -import { z } from 'zod'; -import { getMT4Client, TradeResult } from '../services/mt4-client'; - -// ========================================== -// mt4_execute_trade -// ========================================== - -/** - * mt4_execute_trade - Execute a market order (BUY or SELL) - * - * @description Opens a new trading position with optional SL/TP levels. - * Supports market orders only (pending orders not implemented). - * - * @param symbol - Trading symbol (e.g., "XAUUSD", "EURUSD") - * @param action - Trade direction: "buy" or "sell" - * @param lots - Volume in lots (e.g., 0.01, 0.1, 1.0) - * @param stopLoss - Optional stop loss price - * @param takeProfit - Optional take profit price - * @param slippage - Optional max slippage in points (default: 3) - * @param magic - Optional magic number for EA identification - * @param comment - Optional order comment - * @returns Trade result with ticket number - * - * @example - * // Simple buy order - * const result = await mt4_execute_trade({ - * symbol: "XAUUSD", - * action: "buy", - * lots: 0.1 - * }); - * - * // Buy with SL/TP - * const result = await mt4_execute_trade({ - * symbol: "XAUUSD", - * action: "buy", - * lots: 0.1, - * stopLoss: 2640.00, - * takeProfit: 2680.00, - * comment: "AI Signal" - * }); - */ - -export const mt4ExecuteTradeSchema = { - name: 'mt4_execute_trade', - description: 'Execute a market order (BUY or SELL) on MT4 with optional stop loss and take profit', - inputSchema: { - type: 'object' as const, - properties: { - symbol: { - type: 'string', - description: 'Trading symbol (e.g., XAUUSD, EURUSD, GBPUSD)', - }, - action: { - type: 'string', - enum: ['buy', 'sell'], - description: 'Trade direction: buy or sell', - }, - lots: { - type: 'number', - description: 'Volume in lots (e.g., 0.01, 0.1, 1.0)', - }, - stopLoss: { - type: 'number', - description: 'Optional: Stop loss price level', - }, - takeProfit: { - type: 'number', - description: 'Optional: Take profit price level', - }, - slippage: { - type: 'number', - description: 'Optional: Maximum slippage in points (default: 3)', - }, - magic: { - type: 'number', - description: 'Optional: Magic number for EA identification (default: 12345)', - }, - comment: { - type: 'string', - description: 'Optional: Order comment (max 31 chars)', - }, - }, - required: ['symbol', 'action', 'lots'] as string[], - }, -}; - -export const Mt4ExecuteTradeInputSchema = z.object({ - symbol: z.string().min(1).max(20), - action: z.enum(['buy', 'sell']), - lots: z.number().positive().max(100), - stopLoss: z.number().positive().optional(), - takeProfit: z.number().positive().optional(), - slippage: z.number().int().min(0).max(100).optional(), - magic: z.number().int().optional(), - comment: z.string().max(31).optional(), -}); - -export type Mt4ExecuteTradeInput = z.infer; - -export interface Mt4ExecuteTradeResult { - success: boolean; - data?: TradeResult & { - symbol: string; - action: string; - lots: number; - }; - error?: string; -} - -export async function mt4_execute_trade( - params: Mt4ExecuteTradeInput -): Promise { - try { - const client = getMT4Client(); - - // Check connection - const isConnected = await client.isConnected(); - if (!isConnected) { - return { - success: false, - error: 'MT4 terminal is not connected', - }; - } - - // Validate SL/TP logic (basic check) - if (params.stopLoss !== undefined && params.takeProfit !== undefined) { - if (params.action === 'buy') { - // For buy: SL should be below current price, TP above - if (params.stopLoss >= params.takeProfit) { - return { - success: false, - error: 'For BUY orders, stop loss must be below take profit', - }; - } - } else { - // For sell: SL should be above current price, TP below - if (params.stopLoss <= params.takeProfit) { - return { - success: false, - error: 'For SELL orders, stop loss must be above take profit', - }; - } - } - } - - // Execute trade - const result = await client.executeTrade({ - symbol: params.symbol.toUpperCase(), - action: params.action, - lots: params.lots, - stopLoss: params.stopLoss, - takeProfit: params.takeProfit, - slippage: params.slippage, - magic: params.magic, - comment: params.comment, - }); - - if (result.success) { - return { - success: true, - data: { - ...result, - symbol: params.symbol.toUpperCase(), - action: params.action, - lots: params.lots, - }, - }; - } - - return { - success: false, - error: result.message || 'Trade execution failed', - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleMt4ExecuteTrade( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = Mt4ExecuteTradeInputSchema.parse(params); - const result = await mt4_execute_trade(validatedParams); - - if (result.success && result.data) { - const formattedOutput = ` -Trade Executed Successfully -=========================== -Ticket: #${result.data.ticket} -Symbol: ${result.data.symbol} -Direction: ${result.data.action.toUpperCase()} -Volume: ${result.data.lots} lots -${validatedParams.stopLoss ? `Stop Loss: ${validatedParams.stopLoss}` : 'Stop Loss: Not set'} -${validatedParams.takeProfit ? `Take Profit: ${validatedParams.takeProfit}` : 'Take Profit: Not set'} -Message: ${result.data.message || 'Order placed successfully'} -`.trim(); - - return { - content: [ - { - type: 'text', - text: formattedOutput, - }, - ], - }; - } - - return { - content: [ - { - type: 'text', - text: `Error executing trade: ${result.error}`, - }, - ], - }; -} - -// ========================================== -// mt4_modify_position -// ========================================== - -/** - * mt4_modify_position - Modify SL/TP of an existing position - * - * @description Updates the stop loss and/or take profit levels of an open position. - * - * @param ticket - Position ticket number to modify - * @param stopLoss - New stop loss price (null to remove) - * @param takeProfit - New take profit price (null to remove) - * @returns Modification result - * - * @example - * // Set both SL and TP - * const result = await mt4_modify_position({ - * ticket: 123456, - * stopLoss: 2640.00, - * takeProfit: 2680.00 - * }); - * - * // Update only TP - * const result = await mt4_modify_position({ - * ticket: 123456, - * takeProfit: 2700.00 - * }); - */ - -export const mt4ModifyPositionSchema = { - name: 'mt4_modify_position', - description: 'Modify stop loss and/or take profit of an existing position', - inputSchema: { - type: 'object' as const, - properties: { - ticket: { - type: 'number', - description: 'Position ticket number to modify', - }, - stopLoss: { - type: 'number', - description: 'New stop loss price level (optional)', - }, - takeProfit: { - type: 'number', - description: 'New take profit price level (optional)', - }, - }, - required: ['ticket'] as string[], - }, -}; - -export const Mt4ModifyPositionInputSchema = z.object({ - ticket: z.number().int().positive(), - stopLoss: z.number().positive().optional(), - takeProfit: z.number().positive().optional(), -}); - -export type Mt4ModifyPositionInput = z.infer; - -export interface Mt4ModifyPositionResult { - success: boolean; - data?: TradeResult; - error?: string; -} - -export async function mt4_modify_position( - params: Mt4ModifyPositionInput -): Promise { - try { - const client = getMT4Client(); - - // Check connection - const isConnected = await client.isConnected(); - if (!isConnected) { - return { - success: false, - error: 'MT4 terminal is not connected', - }; - } - - // Validate at least one parameter is provided - if (params.stopLoss === undefined && params.takeProfit === undefined) { - return { - success: false, - error: 'At least one of stopLoss or takeProfit must be provided', - }; - } - - // Verify position exists - const position = await client.getPosition(params.ticket); - if (!position) { - return { - success: false, - error: `Position with ticket ${params.ticket} not found`, - }; - } - - // Validate SL/TP based on position type - const sl = params.stopLoss; - const tp = params.takeProfit; - - if (sl !== undefined && tp !== undefined) { - if (position.type === 'buy') { - if (sl >= tp) { - return { - success: false, - error: 'For BUY positions, stop loss must be below take profit', - }; - } - } else { - if (sl <= tp) { - return { - success: false, - error: 'For SELL positions, stop loss must be above take profit', - }; - } - } - } - - // Modify position - const result = await client.modifyPosition({ - ticket: params.ticket, - stopLoss: params.stopLoss, - takeProfit: params.takeProfit, - }); - - return { - success: result.success, - data: result, - error: result.success ? undefined : result.message, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred', - }; - } -} - -export async function handleMt4ModifyPosition( - params: unknown -): Promise<{ content: Array<{ type: string; text: string }> }> { - const validatedParams = Mt4ModifyPositionInputSchema.parse(params); - const result = await mt4_modify_position(validatedParams); - - if (result.success && result.data) { - const formattedOutput = ` -Position Modified Successfully -============================== -Ticket: #${validatedParams.ticket} -${validatedParams.stopLoss !== undefined ? `New Stop Loss: ${validatedParams.stopLoss}` : 'Stop Loss: Unchanged'} -${validatedParams.takeProfit !== undefined ? `New Take Profit: ${validatedParams.takeProfit}` : 'Take Profit: Unchanged'} -Message: ${result.data.message || 'Position modified successfully'} -`.trim(); - - return { - content: [ - { - type: 'text', - text: formattedOutput, - }, - ], - }; - } - - return { - content: [ - { - type: 'text', - text: `Error modifying position: ${result.error}`, - }, - ], - }; -} diff --git a/apps/mcp-mt4-connector/tsconfig.json b/apps/mcp-mt4-connector/tsconfig.json deleted file mode 100644 index ad10886..0000000 --- a/apps/mcp-mt4-connector/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "commonjs", - "lib": ["ES2022"], - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "tests"] -} diff --git a/mcp-predictions b/apps/mcp-predictions similarity index 100% rename from mcp-predictions rename to apps/mcp-predictions diff --git a/mcp-products b/apps/mcp-products similarity index 100% rename from mcp-products rename to apps/mcp-products diff --git a/mcp-vip b/apps/mcp-vip similarity index 100% rename from mcp-vip rename to apps/mcp-vip diff --git a/mcp-wallet b/apps/mcp-wallet similarity index 100% rename from mcp-wallet rename to apps/mcp-wallet