diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6235fd6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + pull_request: + branches: [main] + +jobs: + ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Check formatting + run: npm run format:check + + - name: Build + run: npm run build + + - name: Test + run: npm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d3541b3..3bb2ec6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,13 +19,25 @@ jobs: - name: Install dependencies run: npm ci - + + - name: Lint + run: npm run lint + + - name: Check formatting + run: npm run format:check + + - name: Test + run: npm test + - name: Sync version with release tag run: npm version ${{ github.event.release.tag_name }} --no-git-tag-version - name: Build package run: npm run build + - name: Audit publish contents + run: npm pack --dry-run + - name: Publish to npmjs run: npm publish --access public env: diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..29f78a6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "trailingComma": "all" +} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..afe2542 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,18 @@ +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import prettierConfig from 'eslint-config-prettier'; + +export default tseslint.config( + js.configs.recommended, + ...tseslint.configs.recommended, + prettierConfig, + { + ignores: ['build/**', 'node_modules/**'], + }, + { + rules: { + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + }, + }, +); diff --git a/package-lock.json b/package-lock.json index 4538ad8..0ef52ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@paystack/mcp-server", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@paystack/mcp-server", - "version": "0.0.1", + "version": "0.0.2", "license": "MIT", "dependencies": { - "@modelcontextprotocol/inspector": "^0.18.0", + "@apidevtools/swagger-parser": "^12.1.0", "@modelcontextprotocol/sdk": "^1.26.0", "dotenv": "^17.2.3", "zod": "^4.3.6" @@ -18,21 +18,28 @@ "paystack-mcp-server": "build/index.js" }, "devDependencies": { - "@apidevtools/swagger-parser": "^12.1.0", + "@eslint/js": "^9.0.0", + "@modelcontextprotocol/inspector": "^0.18.0", "@types/mocha": "^10.0.10", "@types/node": "^25.0.7", + "eslint": "^9.0.0", + "eslint-config-prettier": "^10.0.0", "js-yaml": "^4.1.1", "mocha": "^11.3.0", "openapi-types": "^12.1.3", + "prettier": "^3.0.0", "tsx": "^4.21.0", - "typescript": "^5.9.3" + "typescript": "^5.9.3", + "typescript-eslint": "^8.0.0" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@apidevtools/json-schema-ref-parser": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-14.0.1.tgz", "integrity": "sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw==", - "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.15", @@ -49,7 +56,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -59,14 +65,12 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", - "dev": true, "license": "MIT" }, "node_modules/@apidevtools/swagger-parser": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-12.1.0.tgz", "integrity": "sha512-e5mJoswsnAX0jG+J09xHFYQXb/bUc5S3pLpMxUuRUA2H8T2kni3yEoyz2R3Dltw5f4A6j6rPNMpWTK+iVDFlng==", - "dev": true, "license": "MIT", "dependencies": { "@apidevtools/json-schema-ref-parser": "14.0.1", @@ -84,6 +88,7 @@ "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" @@ -534,10 +539,227 @@ "node": ">=18" } }, + "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/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "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.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "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.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@floating-ui/core": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "dev": true, "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.10" @@ -547,6 +769,7 @@ "version": "1.7.5", "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "dev": true, "license": "MIT", "dependencies": { "@floating-ui/core": "^1.7.4", @@ -557,6 +780,7 @@ "version": "2.1.7", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "dev": true, "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.7.5" @@ -570,6 +794,7 @@ "version": "0.2.10", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "dev": true, "license": "MIT" }, "node_modules/@hono/node-server": { @@ -584,6 +809,58 @@ "hono": "^4" } }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@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/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -606,6 +883,7 @@ "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" @@ -615,12 +893,14 @@ "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.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", @@ -631,6 +911,7 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector/-/inspector-0.18.0.tgz", "integrity": "sha512-aBrBDaI8MtvyS9j3TMRgTHZaOwbe/zh2rbIVplIBtxWifaSfvQX9DbnoI3xv9sZjgeFyF/3CwZdfEVTUx2RfBg==", + "dev": true, "license": "MIT", "workspaces": [ "client", @@ -661,6 +942,7 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector-cli/-/inspector-cli-0.18.0.tgz", "integrity": "sha512-QMPjKx8zKmX17S1LF2gWuwbYglKexkdgB0HhKZFXzGrQ0MYoKUsIgokMyV48xr4LipaLS3b2v3ut3nV/jhWeSg==", + "dev": true, "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.24.3", @@ -675,6 +957,7 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector-client/-/inspector-client-0.18.0.tgz", "integrity": "sha512-M6A5SN09tYCoTTGwMi5hdQpesX5eHYn3FCAHTWfv1pZ1Cy7h5GjB1LxL5WhbMhXWmFFJ6AnQVGAJj0P0XkVhUg==", + "dev": true, "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.24.3", @@ -711,6 +994,7 @@ "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", @@ -727,12 +1011,14 @@ "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/@modelcontextprotocol/inspector-client/node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -742,6 +1028,7 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector-server/-/inspector-server-0.18.0.tgz", "integrity": "sha512-N7mDwUuj+gB8ZbZ52M4Oqh37qChS8kWJUkc4qL/MMsaQTVshXEOTcyiQ/mLKa17O5uODZQerAnQJWZbZYReBkg==", + "dev": true, "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.24.3", @@ -760,6 +1047,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -769,6 +1057,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -838,18 +1127,21 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "dev": true, "license": "MIT" }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "dev": true, "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -873,6 +1165,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -903,6 +1196,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -929,6 +1223,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -947,6 +1242,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -962,6 +1258,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -977,6 +1274,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1013,6 +1311,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1031,6 +1330,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1046,6 +1346,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1073,6 +1374,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1088,6 +1390,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -1113,6 +1416,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "dev": true, "license": "MIT", "peerDependencies": { "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" @@ -1122,6 +1426,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1140,6 +1445,7 @@ "version": "2.1.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.4" @@ -1163,6 +1469,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.4" @@ -1186,6 +1493,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1223,6 +1531,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1241,6 +1550,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "dev": true, "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", @@ -1273,6 +1583,7 @@ "version": "1.1.9", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3", @@ -1297,6 +1608,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -1321,6 +1633,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -1344,6 +1657,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1362,6 +1676,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1393,6 +1708,7 @@ "version": "2.2.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.1", @@ -1436,6 +1752,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1454,6 +1771,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1472,6 +1790,7 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1501,6 +1820,7 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1531,6 +1851,7 @@ "version": "1.2.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1565,6 +1886,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -1599,6 +1921,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1617,6 +1940,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1632,6 +1956,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", @@ -1651,6 +1976,7 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1669,6 +1995,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" @@ -1687,6 +2014,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1702,6 +2030,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1717,6 +2046,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/rect": "1.1.1" @@ -1735,6 +2065,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1753,6 +2084,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -1776,37 +2108,48 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "dev": true, "license": "MIT" }, "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/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, "license": "MIT" }, "node_modules/@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/mocha": { @@ -1820,28 +2163,312 @@ "version": "25.2.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.16.0" } }, - "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==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz", + "integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==", + "dev": true, "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/type-utils": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz", + "integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz", + "integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.58.2", + "@typescript-eslint/types": "^8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz", + "integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz", + "integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz", + "integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz", + "integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz", + "integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.58.2", + "@typescript-eslint/tsconfig-utils": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz", + "integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz", + "integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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/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", "bin": { "acorn": "bin/acorn" @@ -1850,10 +2477,21 @@ "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" @@ -1882,7 +2520,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, "license": "MIT", "peerDependencies": { "ajv": "^8.5.0" @@ -1927,6 +2564,7 @@ "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" @@ -1942,19 +2580,20 @@ "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/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -1967,6 +2606,7 @@ "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/body-parser": { @@ -2014,6 +2654,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" @@ -2067,9 +2708,18 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", - "dev": true, "license": "MIT" }, + "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": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -2087,6 +2737,7 @@ "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", @@ -2103,6 +2754,7 @@ "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" @@ -2131,6 +2783,7 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "dev": true, "license": "Apache-2.0", "dependencies": { "clsx": "^2.1.1" @@ -2143,6 +2796,7 @@ "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", @@ -2157,6 +2811,7 @@ "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" @@ -2166,12 +2821,14 @@ "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/cliui/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", @@ -2186,6 +2843,7 @@ "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" @@ -2198,6 +2856,7 @@ "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", @@ -2215,6 +2874,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2224,6 +2884,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "dev": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", @@ -2240,6 +2901,7 @@ "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" @@ -2252,12 +2914,14 @@ "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/commander": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -2267,12 +2931,14 @@ "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/concurrently": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "4.1.2", @@ -2354,6 +3020,7 @@ "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": { @@ -2374,6 +3041,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 12" @@ -2409,10 +3077,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/default-browser": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -2429,6 +3105,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -2441,6 +3118,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -2462,6 +3140,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "dev": true, "license": "MIT" }, "node_modules/diff": { @@ -2605,6 +3284,7 @@ "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" @@ -2629,6 +3309,224 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "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.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "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.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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", @@ -2730,6 +3628,14 @@ "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": { @@ -2748,10 +3654,29 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, "funding": [ { "type": "github", @@ -2771,6 +3696,19 @@ "node": "^12.20 || >= 14.13" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/finalhandler": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", @@ -2809,15 +3747,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } + "license": "ISC" }, "node_modules/foreground-child": { "version": "3.3.1", @@ -2840,6 +3799,7 @@ "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, "license": "MIT", "dependencies": { "fetch-blob": "^3.1.2" @@ -2894,6 +3854,7 @@ "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.*" @@ -2927,6 +3888,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2979,6 +3941,32 @@ "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/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2995,6 +3983,7 @@ "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" @@ -3079,6 +4068,43 @@ "url": "https://opencollective.com/express" } }, + "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/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/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3107,6 +4133,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -3118,19 +4145,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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-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-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^3.0.0" @@ -3188,6 +4240,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" @@ -3234,13 +4287,13 @@ "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" @@ -3249,6 +4302,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -3261,6 +4321,37 @@ "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/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/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/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -3277,6 +4368,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -3298,6 +4396,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -3317,6 +4416,7 @@ "version": "0.523.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.523.0.tgz", "integrity": "sha512-rUjQoy7egZT9XYVXBK1je9ckBnNp7qzRZOhLQx5RcEp2dCGlXo+mv6vf7Am4LimEcFBJIIZzSGfgTqc9QCrPSw==", + "dev": true, "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -3326,6 +4426,7 @@ "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/math-intrinsics": { @@ -3452,6 +4553,13 @@ "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": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -3466,6 +4574,7 @@ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "deprecated": "Use your platform's native DOMException instead", + "dev": true, "funding": [ { "type": "github", @@ -3485,6 +4594,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -3545,6 +4655,7 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, "license": "MIT", "dependencies": { "default-browser": "^5.2.1", @@ -3563,9 +4674,26 @@ "version": "12.1.3", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", - "dev": true, "license": "MIT" }, + "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", @@ -3605,6 +4733,19 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "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/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -3628,6 +4769,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true, "license": "(WTFPL OR MIT)" }, "node_modules/path-key": { @@ -3673,19 +4815,60 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pkce-challenge": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz", "integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.20.0" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prismjs": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3708,6 +4891,7 @@ "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" @@ -3766,6 +4950,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -3778,6 +4963,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -3791,6 +4977,7 @@ "version": "2.7.2", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "dev": true, "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", @@ -3816,6 +5003,7 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "dev": true, "license": "MIT", "dependencies": { "react-style-singleton": "^2.2.2", @@ -3838,6 +5026,7 @@ "version": "0.14.1", "resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.14.1.tgz", "integrity": "sha512-BR5DtNRy+AswWJECyA17qhUDvrrCZ6zXOCfkQY5zSmb96BVUbpVAv03WpcjcwtCwiLbIANx3gebHOcXYn1EHow==", + "dev": true, "license": "MIT", "peerDependencies": { "react": ">=16.8.0", @@ -3848,6 +5037,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "dev": true, "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", @@ -3884,6 +5074,7 @@ "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" @@ -3898,6 +5089,16 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -3928,6 +5129,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3940,6 +5142,7 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" @@ -3976,11 +5179,25 @@ "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", @@ -4021,6 +5238,7 @@ "version": "6.1.6", "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "3.0.0", @@ -4036,6 +5254,7 @@ "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", @@ -4046,6 +5265,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -4055,6 +5275,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -4064,6 +5285,7 @@ "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -4073,6 +5295,7 @@ "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "~1.33.0" @@ -4085,6 +5308,7 @@ "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" @@ -4097,12 +5321,14 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "dev": true, "license": "MIT" }, "node_modules/serve-handler/node_modules/range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -4158,6 +5384,7 @@ "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4255,6 +5482,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-5.1.2.tgz", "integrity": "sha512-/y7tJKALVZ1lPzeZZB9jYnmtrL7d0N2zkorii5a7r7dhHkWIuLTzZpZzMJLK1dmYRgX/NCc4iarTO3F7BS2c/A==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.7", @@ -4391,6 +5619,7 @@ "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" @@ -4406,12 +5635,30 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", + "dev": true, "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" } }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -4425,15 +5672,30 @@ "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": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "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", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -4477,6 +5739,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -4486,6 +5749,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, "license": "0BSD" }, "node_modules/tsx": { @@ -4508,6 +5772,19 @@ "fsevents": "~2.3.3" } }, + "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-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -4526,6 +5803,7 @@ "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", "bin": { "tsc": "bin/tsc", @@ -4535,10 +5813,35 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.2.tgz", + "integrity": "sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.58.2", + "@typescript-eslint/parser": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, "license": "MIT" }, "node_modules/unpipe": { @@ -4554,6 +5857,7 @@ "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" @@ -4563,6 +5867,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -4584,6 +5889,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "dev": true, "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", @@ -4606,6 +5912,7 @@ "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/vary": { @@ -4621,6 +5928,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -4641,6 +5949,16 @@ "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/workerpool": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", @@ -4753,6 +6071,7 @@ "version": "8.19.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -4774,6 +6093,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, "license": "MIT", "dependencies": { "is-wsl": "^3.1.0" @@ -4789,6 +6109,7 @@ "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" @@ -4798,6 +6119,7 @@ "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", @@ -4816,6 +6138,7 @@ "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" @@ -4841,6 +6164,7 @@ "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" @@ -4850,12 +6174,14 @@ "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/yargs/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", @@ -4870,6 +6196,7 @@ "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" @@ -4882,6 +6209,7 @@ "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" diff --git a/package.json b/package.json index 163b25f..8fcb4e4 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,17 @@ "build": "tsc && cp -r src/data build/", "build:watch": "tsc --watch", "prepack": "npm run build", + "prepublishOnly": "npm run build && npm test", "dev": "tsx src/index.ts", "inspect": "set DANGEROUSLY_OMIT_AUTH=true && CLIENT_PORT=8090 SERVER_PORT=9000 npx @modelcontextprotocol/inspector npm run dev", - "test": "mocha" + "test": "mocha", + "lint": "eslint src/ test/", + "lint:fix": "eslint src/ test/ --fix", + "format:check": "prettier --check src/ test/", + "format": "prettier --write src/ test/" + }, + "engines": { + "node": ">=20.0.0" }, "files": [ "build", "README.md" ], "keywords": [ @@ -30,19 +38,24 @@ "author": "Andrew-Paystack", "license": "MIT", "dependencies": { - "@modelcontextprotocol/inspector": "^0.18.0", "@modelcontextprotocol/sdk": "^1.26.0", + "@apidevtools/swagger-parser": "^12.1.0", "dotenv": "^17.2.3", "zod": "^4.3.6" }, "devDependencies": { - "@apidevtools/swagger-parser": "^12.1.0", + "@eslint/js": "^9.0.0", + "@modelcontextprotocol/inspector": "^0.18.0", "@types/mocha": "^10.0.10", "@types/node": "^25.0.7", + "eslint": "^9.0.0", + "eslint-config-prettier": "^10.0.0", "js-yaml": "^4.1.1", "mocha": "^11.3.0", "openapi-types": "^12.1.3", + "prettier": "^3.0.0", "tsx": "^4.21.0", - "typescript": "^5.9.3" + "typescript": "^5.9.3", + "typescript-eslint": "^8.0.0" } } diff --git a/src/config.ts b/src/config.ts index 189c98e..2f6ae12 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,27 +1,29 @@ import dotenv from 'dotenv'; // Load environment variables from .env file -dotenv.config({quiet: true}); +dotenv.config({ quiet: true }); // Get configuration with optional CLI API key export function getConfig(cliApiKey?: string) { const apiKey = cliApiKey || process.env.PAYSTACK_TEST_SECRET_KEY; - + if (!apiKey) { console.error('Error: PAYSTACK_TEST_SECRET_KEY is required'); process.exit(1); } - + if (!apiKey.startsWith('sk_test_')) { - console.error('Error: PAYSTACK_TEST_SECRET_KEY must begin with "sk_test_". No live keys allowed.'); + console.error( + 'Error: PAYSTACK_TEST_SECRET_KEY must begin with "sk_test_". No live keys allowed.', + ); process.exit(1); } - + if (apiKey.length < 30) { console.error('Error: PAYSTACK_TEST_SECRET_KEY appears to be too short'); process.exit(1); } - + return { PAYSTACK_TEST_SECRET_KEY: apiKey, NODE_ENV: (process.env.NODE_ENV as 'development' | 'production' | 'test') || 'development', diff --git a/src/data/paystack-skill.md b/src/data/paystack-skill.md index 8b44246..de91334 100644 --- a/src/data/paystack-skill.md +++ b/src/data/paystack-skill.md @@ -15,28 +15,32 @@ This index covers payments, transfers, terminal, guides, libraries, API referenc Code snippets for Paystack API endpoints and integration guides are maintained in the PaystackOSS/doc-code-snippets repository. Snippets are available in JavaScript (Node.js), Shell/cURL, and PHP. ### Browsing Snippets + - API Reference snippets: https://github.com/PaystackOSS/doc-code-snippets/tree/main/src/api - Documentation snippets: https://github.com/PaystackOSS/doc-code-snippets/tree/main/src/doc ### Fetching a Specific Snippet + Once you know the exact path from browsing, fetch the raw content at: https://raw.githubusercontent.com/PaystackOSS/doc-code-snippets/main/src/api/{topic}/{action}/index.{js,sh} For example: + - https://raw.githubusercontent.com/PaystackOSS/doc-code-snippets/main/src/api/transactions/initialize/index.js - https://raw.githubusercontent.com/PaystackOSS/doc-code-snippets/main/src/api/transactions/initialize/index.sh ### Snippet Notes + - Snippets use placeholder values like "SECRET_KEY" or "YOUR_SECRET_KEY" — replace with actual test keys - Not every endpoint has a snippet; if unavailable, construct the request from the operation details provided by the "get_paystack_operation" tool -- The supported webhook events are in https://raw.githubusercontent.com/PaystackOSS/doc-code-snippets/main/dist/doc/payments/webhooks/events.js +- The supported webhook events are in https://raw.githubusercontent.com/PaystackOSS/doc-code-snippets/main/dist/doc/payments/webhooks/events.js ## Payment Channels by Country -| Country | Currencies | Payment Channels | -|---------|----------|-----------------| -| Nigeria | NGN, USD | Cards (Visa, Mastercard, Verve, Amex), Bank Transfer, USSD, QR Code, Apple Pay | -| Ghana | GHS | Cards (Visa, Mastercard, Verve), Mobile Money (MTN, AirtelTigo, Telecel), Bank Transfer, QR Code | -| South Africa | ZAR | Cards (Visa, Mastercard, Verve, Amex), Apple Pay, Scan to Pay, Capitec Pay, Ozow | -| Kenya | KES, USD | Cards (Visa, Mastercard, Verve), Mobile Money (M-PESA, Airtel Money), Bank Transfers (Pesalink) -| Côte d'Ivoire | XOF | Cards (Visa, Mastercard, Verve), Mobile Money (MTN MoMo, Wave, Orange Money), Apple Pay | \ No newline at end of file +| Country | Currencies | Payment Channels | +| ------------- | ---------- | ------------------------------------------------------------------------------------------------ | +| Nigeria | NGN, USD | Cards (Visa, Mastercard, Verve, Amex), Bank Transfer, USSD, QR Code, Apple Pay | +| Ghana | GHS | Cards (Visa, Mastercard, Verve), Mobile Money (MTN, AirtelTigo, Telecel), Bank Transfer, QR Code | +| South Africa | ZAR | Cards (Visa, Mastercard, Verve, Amex), Apple Pay, Scan to Pay, Capitec Pay, Ozow | +| Kenya | KES, USD | Cards (Visa, Mastercard, Verve), Mobile Money (M-PESA, Airtel Money), Bank Transfers (Pesalink) | +| Côte d'Ivoire | XOF | Cards (Visa, Mastercard, Verve), Mobile Money (MTN MoMo, Wave, Orange Money), Apple Pay | diff --git a/src/data/paystack.openapi.yaml b/src/data/paystack.openapi.yaml index 9663923..a798e5c 100644 --- a/src/data/paystack.openapi.yaml +++ b/src/data/paystack.openapi.yaml @@ -19140,4 +19140,4 @@ components: content: application/json: schema: - $ref: '#/components/schemas/MiscellaneousListStatesResponse' \ No newline at end of file + $ref: '#/components/schemas/MiscellaneousListStatesResponse' diff --git a/src/index.ts b/src/index.ts index 0256b0b..4d6d9a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,12 +2,12 @@ // Simple CLI argument parsing function parseApiKey(): string | undefined { const args = process.argv; - const apiKeyIndex = args.findIndex(arg => arg === '--api-key'); - + const apiKeyIndex = args.findIndex((arg) => arg === '--api-key'); + if (apiKeyIndex !== -1 && apiKeyIndex + 1 < args.length) { return args[apiKeyIndex + 1]; } - + return undefined; } @@ -39,24 +39,25 @@ async function main() { process.exit(0); } - const { startServer } = await import("./server"); + const { startServer } = await import('./server'); // Parse API key from CLI const cliApiKey = parseApiKey(); - - + // Check if we have an API key from CLI or environment if (!cliApiKey && !process.env.PAYSTACK_TEST_SECRET_KEY) { console.error('Error: Paystack API key required.'); - console.error('Provide via --api-key argument or PAYSTACK_TEST_SECRET_KEY environment variable.'); + console.error( + 'Provide via --api-key argument or PAYSTACK_TEST_SECRET_KEY environment variable.', + ); showHelp(); process.exit(1); } - + await startServer(cliApiKey); } main().catch((error) => { - console.error("Fatal error in main():", error); + console.error('Fatal error in main():', error); process.exit(1); -}); \ No newline at end of file +}); diff --git a/src/logger.ts b/src/logger.ts index a6aa82d..7cdc39a 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -35,7 +35,7 @@ function redactCardObject(card: any): any { if (Array.isArray(card)) { return card.map(redactCardObject); } - + if (typeof card === 'object' && card !== null) { const redactedCard: any = {}; for (const [key, value] of Object.entries(card)) { @@ -49,11 +49,10 @@ function redactCardObject(card: any): any { } return redactedCard; } - + return card; } - function redactSensitiveData(obj: any): any { if (obj === null || obj === undefined) { return obj; @@ -61,8 +60,9 @@ function redactSensitiveData(obj: any): any { if (typeof obj === 'string') { // Redact bearer tokens and API keys in strings - return obj.replace(/Bearer\s+\w+/gi, 'Bearer [REDACTED]') - .replace(/sk_test_\w+/g, '[REDACTED_SECRET_KEY]'); + return obj + .replace(/Bearer\s+\w+/gi, 'Bearer [REDACTED]') + .replace(/sk_test_\w+/g, '[REDACTED_SECRET_KEY]'); } if (Array.isArray(obj)) { @@ -75,9 +75,9 @@ function redactSensitiveData(obj: any): any { // Special handling for card objects - only redact cvv and number if (key.toLowerCase() === 'card' && typeof value === 'object' && value !== null) { redacted[key] = redactCardObject(value); - } + } // Check if key matches sensitive patterns - else if (SENSITIVE_PATTERNS.some(pattern => pattern.test(key))) { + else if (SENSITIVE_PATTERNS.some((pattern) => pattern.test(key))) { redacted[key] = '[REDACTED]'; } else { redacted[key] = redactSensitiveData(value); diff --git a/src/openapi-parser.ts b/src/openapi-parser.ts index 7edb595..a45ed53 100644 --- a/src/openapi-parser.ts +++ b/src/openapi-parser.ts @@ -16,56 +16,46 @@ export class OpenAPIParser { async parse() { try { - const api = (await SwaggerParser.default.parse( - this.specURL - )) as OpenAPIV3.Document; + const api = (await SwaggerParser.default.parse(this.specURL)) as OpenAPIV3.Document; this.buildOperationsMap(api); } catch (error) { console.error('Error parsing OpenAPI spec:', error); } } - private parseModel( - name: string, - models: OpenAPIV3.ComponentsObject, - ): Oas.Body { - const { schemas } = models! + private parseModel(name: string, models: OpenAPIV3.ComponentsObject): Oas.Body { + const { schemas } = models!; const model = schemas![name] as OpenAPIV3.SchemaObject; const body = {} as Oas.Body; - body.properties = [] + body.properties = []; if (model.properties === undefined) { - body.properties.push({ ...model as Oas.BodyParam }) - return body + body.properties.push({ ...(model as Oas.BodyParam) }); + return body; } const { properties, required, example } = model; Object.entries(properties).forEach(([key, property]) => { - let bodyParam = {} as Oas.BodyParam + let bodyParam = {} as Oas.BodyParam; - if ("$ref" in property) { - const name = property.$ref.split("/").pop()!; + if ('$ref' in property) { + const name = property.$ref.split('/').pop()!; // TODO: Consider parsing inner examples if available // Maybe just merge to the top example - const { properties: innerParams } = this.parseModel(name, models) + const { properties: innerParams } = this.parseModel(name, models); bodyParam = { - ...innerParams[0] - } - bodyParam.name = key + ...innerParams[0], + }; + bodyParam.name = key; } else { - const tempProperty = property as OpenAPIV3.SchemaObject + const tempProperty = property as OpenAPIV3.SchemaObject; bodyParam = { name: key, type: tempProperty.type!, - description: tempProperty.description ?? "", - required: - required === undefined - ? false - : required.includes(key) - ? true - : false, + description: tempProperty.description ?? '', + required: required === undefined ? false : required.includes(key) ? true : false, }; } @@ -73,7 +63,7 @@ export class OpenAPIParser { }); if (example !== undefined) { - body.examples = example as Map + body.examples = example as Map; } return body; } @@ -82,81 +72,78 @@ export class OpenAPIParser { schema: Oas.PropertySchema, models: OpenAPIV3.ComponentsObject, ): Oas.Body { - - if ("$ref" in schema) { - const name = schema.$ref.split("/").pop()!; + if ('$ref' in schema) { + const name = schema.$ref.split('/').pop()!; const body = this.parseModel(name, models); return body; } - const body = {} as Oas.Body - body.properties = [] + const body = {} as Oas.Body; + body.properties = []; - if ("type" in schema && schema.type === "array") { + if ('type' in schema && schema.type === 'array') { const schemaPath = schema.items as OpenAPIV3.ReferenceObject; - const name = schemaPath.$ref.split("/").pop() + const name = schemaPath.$ref.split('/').pop(); - const { properties, examples } = this.parseModel(name!, models) + const { properties, examples } = this.parseModel(name!, models); const parent = { - name: "", + name: '', type: 'array', required: true, - description: schema.description ?? "", - children: properties - } as Oas.BodyParam + description: schema.description ?? '', + children: properties, + } as Oas.BodyParam; - body.properties.push(parent) - body.examples = examples + body.properties.push(parent); + body.examples = examples; return body; } - if ("type" in schema && schema.type === "object") { + if ('type' in schema && schema.type === 'object') { const [key, path] = Object.entries(schema.properties!)[0]; - const schemaPath = path as OpenAPIV3.ReferenceObject - const name = schemaPath.$ref.split("/").pop()!; - const { properties, examples } = this.parseModel(name, models) + const schemaPath = path as OpenAPIV3.ReferenceObject; + const name = schemaPath.$ref.split('/').pop()!; + const { properties, examples } = this.parseModel(name, models); const parent = { name: key, type: 'object', required: schema.required ?? false, - description: schema.description ?? "", - children: properties - } as Oas.BodyParam + description: schema.description ?? '', + children: properties, + } as Oas.BodyParam; - body.properties.push(parent) - body.examples = examples + body.properties.push(parent); + body.examples = examples; return body; } - if ("allOf" in schema) { + if ('allOf' in schema) { // An object is being used here because the OAS examples are actually of // the object type even though they're typed as Map // Also, map isn't being parsed properly when writing to file - let mergedExamples = {} + let mergedExamples = {}; schema.allOf?.forEach((schema) => { - const { properties, examples } = this.parseRequestBody(schema, models) - body.properties.push(...properties) + const { properties, examples } = this.parseRequestBody(schema, models); + body.properties.push(...properties); if (examples !== undefined) { - mergedExamples = { ...mergedExamples, ...examples } + mergedExamples = { ...mergedExamples, ...examples }; } }); - body.examples = mergedExamples as Map + body.examples = mergedExamples as Map; - return body + return body; } return {} as Oas.Body; } - private parseParameters( - parameters: OpenAPIV3.ParameterObject[] - ): Oas.RequestParameter { - let result: Oas.RequestParameter = { + private parseParameters(parameters: OpenAPIV3.ParameterObject[]): Oas.RequestParameter { + const result: Oas.RequestParameter = { // header: [], pathParameter: [], queryParameter: [], @@ -165,17 +152,17 @@ export class OpenAPIParser { parameters.forEach((parameter) => { const endpointParam: Oas.EndpointParam = { name: parameter.name, - description: parameter.description ?? "", + description: parameter.description ?? '', required: parameter.required ?? false, schema: parameter.schema as OpenAPIV3.SchemaObject, example: parameter.example, }; - if (parameter.in === "query") { + if (parameter.in === 'query') { result.queryParameter.push(endpointParam); } - if (parameter.in === "path") { + if (parameter.in === 'path') { result.pathParameter.push(endpointParam); } }); @@ -214,31 +201,31 @@ export class OpenAPIParser { if (requestBody !== undefined) { const { content } = requestBody as OpenAPIV3.RequestBodyObject; - const mediaType = content["application/json"]; + const mediaType = content['application/json']; const body = mediaType.schema === undefined - ? {} as Oas.Body + ? ({} as Oas.Body) : this.parseRequestBody(mediaType.schema, components!); - partialOperation.requestBody = body + partialOperation.requestBody = body; } if (parameters && parameters !== null && parameters.length > 0) { - const { pathParameter, queryParameter } = - this.parseParameters(parameters as OpenAPIV3.ParameterObject[]); + const { pathParameter, queryParameter } = this.parseParameters( + parameters as OpenAPIV3.ParameterObject[], + ); // partialOperation.header = header; partialOperation.pathParameter = pathParameter; partialOperation.queryParameter = queryParameter; } - this.operations[operationId!] = partialOperation + this.operations[operationId!] = partialOperation; }); }); } - getOperationById(operationId: string): Partial | undefined { return this.operations[operationId]; } @@ -246,4 +233,4 @@ export class OpenAPIParser { getOperations(): Record> { return this.operations; } -} \ No newline at end of file +} diff --git a/src/paystack-client.ts b/src/paystack-client.ts index b539751..89dd8ed 100644 --- a/src/paystack-client.ts +++ b/src/paystack-client.ts @@ -1,5 +1,5 @@ -import { PaystackResponse, PaystackError } from "./types"; -import { createPaystackConfig } from "./config"; +import { PaystackResponse, PaystackError } from './types'; +import { createPaystackConfig } from './config'; const PAYSTACK_BASE_URL = 'https://api.paystack.co'; const USER_AGENT = process.env.USER_AGENT || 'Paystack-MCP-Server/0.0.1'; @@ -14,10 +14,10 @@ export class PaystackClient { secretKey: string, baseUrl: string = PAYSTACK_BASE_URL, userAgent: string = USER_AGENT, - timeout: number = 30000 + timeout: number = 30000, ) { if (!secretKey) { - throw new Error("Paystack secret key is required"); + throw new Error('Paystack secret key is required'); } this.secretKey = secretKey; @@ -33,22 +33,17 @@ export class PaystackClient { * @param data - Request body for POST/PUT/PATCH or query params for GET */ - async makeRequest( - method: string, - endpoint: string, - data?: any - ): Promise> { - - let url = `${this.baseUrl}${endpoint}`; + async makeRequest(method: string, endpoint: string, data?: any): Promise> { + const url = `${this.baseUrl}${endpoint}`; const headers: Record = { - 'Authorization': `Bearer ${this.secretKey}`, + Authorization: `Bearer ${this.secretKey}`, 'User-Agent': this.userAgent, - 'Accept': 'application/json', + Accept: 'application/json', }; const options: RequestInit = { - method: method.toUpperCase() + method: method.toUpperCase(), }; // Add Content-Type and body for requests with data @@ -67,11 +62,10 @@ export class PaystackClient { try { responseData = JSON.parse(responseText); - } catch (parseError) { + } catch { // Handle non-JSON responses gracefully (e.g., HTML error pages from API gateways) - const responseSnippet = responseText.length > 200 - ? responseText.substring(0, 200) + '...' - : responseText; + const responseSnippet = + responseText.length > 200 ? responseText.substring(0, 200) + '...' : responseText; const errorMessage = `Received non-JSON response from server (HTTP ${response.status}): ${responseSnippet}`; const nonJsonError = new Error(errorMessage); (nonJsonError as any).statusCode = response.status; @@ -80,7 +74,6 @@ export class PaystackClient { } return responseData as PaystackResponse; } catch (error) { - if (error !== null && (error as any).name === 'NetworkError') { const timeoutError = new Error(`Request timeout after ${this.timeout} ms`); (timeoutError as any).statusCode = 408; @@ -88,8 +81,7 @@ export class PaystackClient { } throw error; } - -} + } } /** diff --git a/src/resources/index.ts b/src/resources/index.ts index 74dc2d6..a68586d 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,12 +1,12 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { OpenAPIParser } from "../openapi-parser"; -import { registerOperationListResource } from "./paystack-operation-list"; -import { registerSkillResource } from "./paystack-skill"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { OpenAPIParser } from '../openapi-parser'; +import { registerOperationListResource } from './paystack-operation-list'; +import { registerSkillResource } from './paystack-skill'; export function registerAllResources( server: McpServer, openapi: OpenAPIParser, - skillContent: string + skillContent: string, ) { registerOperationListResource(server, openapi); registerSkillResource(server, skillContent); diff --git a/src/resources/paystack-operation-list.ts b/src/resources/paystack-operation-list.ts index 3c45776..c0c903f 100644 --- a/src/resources/paystack-operation-list.ts +++ b/src/resources/paystack-operation-list.ts @@ -1,17 +1,14 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { OpenAPIParser } from "../openapi-parser"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { OpenAPIParser } from '../openapi-parser'; -export function registerOperationListResource( - server: McpServer, - openapi: OpenAPIParser -) { +export function registerOperationListResource(server: McpServer, openapi: OpenAPIParser) { server.registerResource( - "paystack_operation_list", - "paystack://operations/list", + 'paystack_operation_list', + 'paystack://operations/list', { - description: "Retrieve all Paystack API details", - title: "Paystack API details", - mimeType: "application/json", + description: 'Retrieve all Paystack API details', + title: 'Paystack API details', + mimeType: 'application/json', }, async (uri) => { const operations = openapi.getOperations(); @@ -21,19 +18,21 @@ export function registerOperationListResource( contents: [ { uri: uri.href, - text: JSON.stringify({"message": "Unable to retrive all operations"}), - mimeType: "application/json", + text: JSON.stringify({ message: 'Unable to retrive all operations' }), + mimeType: 'application/json', }, - ] - } + ], + }; } - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(operations, null, 2), - mimeType: "application/json" - }] + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(operations, null, 2), + mimeType: 'application/json', + }, + ], }; - } + }, ); } diff --git a/src/resources/paystack-skill.ts b/src/resources/paystack-skill.ts index 5f292de..3396ac9 100644 --- a/src/resources/paystack-skill.ts +++ b/src/resources/paystack-skill.ts @@ -1,14 +1,14 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; export function registerSkillResource(server: McpServer, skillContent: string) { server.registerResource( - "paystack_skill", - "paystack://skill", + 'paystack_skill', + 'paystack://skill', { description: - "Paystack developer knowledge: docs index pointer, code snippet URL patterns, and payment channel reference", - title: "Paystack Developer Knowledge", - mimeType: "text/markdown", + 'Paystack developer knowledge: docs index pointer, code snippet URL patterns, and payment channel reference', + title: 'Paystack Developer Knowledge', + mimeType: 'text/markdown', }, async (uri) => { return { @@ -16,10 +16,10 @@ export function registerSkillResource(server: McpServer, skillContent: string) { { uri: uri.href, text: skillContent, - mimeType: "text/markdown", + mimeType: 'text/markdown', }, ], }; - } + }, ); } diff --git a/src/server.ts b/src/server.ts index e3bed24..83b79b8 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,10 +1,10 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import path from "path"; -import { OpenAPIParser } from "./openapi-parser"; -import { registerAllTools } from "./tools"; -import { registerAllResources } from "./resources"; -import { loadSkillContent } from "./skill-loader"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import path from 'path'; +import { OpenAPIParser } from './openapi-parser'; +import { registerAllTools } from './tools'; +import { registerAllResources } from './resources'; +import { loadSkillContent } from './skill-loader'; const SERVER_INSTRUCTIONS = `You are connected to the Paystack MCP Server, which provides access to the full Paystack API. @@ -30,19 +30,22 @@ Always call "get_paystack_operation" to get endpoint details before calling "mak `; async function createServer(cliApiKey?: string) { - const server = new McpServer({ - name: "paystack", - version: "0.0.1", - }, { - instructions: SERVER_INSTRUCTIONS, - }); - - const oasPath = path.join(__dirname, "./", "data/paystack.openapi.yaml"); + const server = new McpServer( + { + name: 'paystack', + version: '0.0.1', + }, + { + instructions: SERVER_INSTRUCTIONS, + }, + ); + + const oasPath = path.join(__dirname, './', 'data/paystack.openapi.yaml'); const openapi = new OpenAPIParser(oasPath); await openapi.parse(); - const bundledSkillPath = path.join(__dirname, "data", "paystack-skill.md"); + const bundledSkillPath = path.join(__dirname, 'data', 'paystack-skill.md'); const skillContent = await loadSkillContent(bundledSkillPath); registerAllTools(server, openapi, cliApiKey); @@ -55,6 +58,6 @@ export async function startServer(cliApiKey?: string) { const server = await createServer(cliApiKey); const transport = new StdioServerTransport(); await server.connect(transport); - console.error("Paystack MCP Server running on stdio..."); + console.error('Paystack MCP Server running on stdio...'); return server; -} \ No newline at end of file +} diff --git a/src/skill-loader.ts b/src/skill-loader.ts index 7b3d53b..459151b 100644 --- a/src/skill-loader.ts +++ b/src/skill-loader.ts @@ -1,12 +1,12 @@ -import * as fs from "node:fs/promises"; -import * as path from "node:path"; -import { homedir } from "node:os"; +import * as fs from 'node:fs/promises'; +import * as path from 'node:path'; +import { homedir } from 'node:os'; const DEFAULT_SKILL_URL = - "https://raw.githubusercontent.com/PaystackOSS/paystack-mcp-server/main/src/data/paystack-skill.md"; + 'https://raw.githubusercontent.com/PaystackOSS/paystack-mcp-server/main/src/data/paystack-skill.md'; -const CACHE_DIR = path.join(homedir(), ".paystack-mcp"); -const CACHE_PATH = path.join(CACHE_DIR, "skill-cache.md"); +const CACHE_DIR = path.join(homedir(), '.paystack-mcp'); +const CACHE_PATH = path.join(CACHE_DIR, 'skill-cache.md'); const MAX_AGE_MS = 48 * 60 * 60 * 1000; // 48 hours export async function loadSkillContent(bundledPath: string): Promise { @@ -16,7 +16,7 @@ export async function loadSkillContent(bundledPath: string): Promise { // Check disk cache freshness const stat = await fs.stat(CACHE_PATH); if (Date.now() - stat.mtimeMs < MAX_AGE_MS) { - return await fs.readFile(CACHE_PATH, "utf-8"); + return await fs.readFile(CACHE_PATH, 'utf-8'); } } catch { // Cache missing or unreadable — continue to fetch @@ -26,10 +26,10 @@ export async function loadSkillContent(bundledPath: string): Promise { const res = await fetch(url, { signal: AbortSignal.timeout(3000) }); if (res.ok) { const text = await res.text(); - if (text.includes("name: paystack")) { + if (text.includes('name: paystack')) { try { await fs.mkdir(CACHE_DIR, { recursive: true }); - await fs.writeFile(CACHE_PATH, text, "utf-8"); + await fs.writeFile(CACHE_PATH, text, 'utf-8'); } catch { // Cache write failed — non-fatal } @@ -42,8 +42,8 @@ export async function loadSkillContent(bundledPath: string): Promise { // Fallback: stale cache → bundled file try { - return await fs.readFile(CACHE_PATH, "utf-8"); + return await fs.readFile(CACHE_PATH, 'utf-8'); } catch { - return await fs.readFile(bundledPath, "utf-8"); + return await fs.readFile(bundledPath, 'utf-8'); } } diff --git a/src/tools/get-paystack-operation.ts b/src/tools/get-paystack-operation.ts index 148ac88..264dc8c 100644 --- a/src/tools/get-paystack-operation.ts +++ b/src/tools/get-paystack-operation.ts @@ -1,27 +1,24 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import * as z from "zod"; -import { OpenAPIParser } from "../openapi-parser"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import * as z from 'zod'; +import { OpenAPIParser } from '../openapi-parser'; -export function registerGetPaystackOperationTool( - server: McpServer, - openapi: OpenAPIParser -) { +export function registerGetPaystackOperationTool(server: McpServer, openapi: OpenAPIParser) { const operations = openapi.getOperations(); server.registerTool( - "get_paystack_operation", + 'get_paystack_operation', { description: `Get Paystack API operation details by operation ID. Available operations are: - ${Object.keys(operations).map(operation => operation).join(", ") }`, + ${Object.keys(operations) + .map((operation) => operation) + .join(', ')}`, annotations: { - title: "Get endpoint details by operation ID", + title: 'Get endpoint details by operation ID', }, inputSchema: { - operation_id: z - .string() - .describe("The operation ID of the Paystack API endpoint"), - } + operation_id: z.string().describe('The operation ID of the Paystack API endpoint'), + }, }, async ({ operation_id }) => { try { @@ -31,35 +28,35 @@ export function registerGetPaystackOperationTool( return { content: [ { - type: "text", + type: 'text', text: `Operation with ID ${operation_id} not found.`, }, ], - isError: true - } + isError: true, + }; } return { content: [ { - type: "text", + type: 'text', text: JSON.stringify(operation, null, 2), - mimeType: "application/json", + mimeType: 'application/json', }, - ] - } + ], + }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { - type: "text", + type: 'text', text: `Error retrieving operation: ${errorMessage}`, }, ], - isError: true - } + isError: true, + }; } - } + }, ); } diff --git a/src/tools/index.ts b/src/tools/index.ts index e63eb49..18658de 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,13 +1,9 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { OpenAPIParser } from "../openapi-parser"; -import { registerGetPaystackOperationTool } from "./get-paystack-operation"; -import { registerMakePaystackRequestTool } from "./make-paystack-request"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { OpenAPIParser } from '../openapi-parser'; +import { registerGetPaystackOperationTool } from './get-paystack-operation'; +import { registerMakePaystackRequestTool } from './make-paystack-request'; -export function registerAllTools( - server: McpServer, - openapi: OpenAPIParser, - cliApiKey?: string -) { +export function registerAllTools(server: McpServer, openapi: OpenAPIParser, cliApiKey?: string) { registerGetPaystackOperationTool(server, openapi); registerMakePaystackRequestTool(server, cliApiKey); } diff --git a/src/tools/make-paystack-request.ts b/src/tools/make-paystack-request.ts index 6adce0d..409c999 100644 --- a/src/tools/make-paystack-request.ts +++ b/src/tools/make-paystack-request.ts @@ -1,52 +1,52 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import * as z from "zod"; -import { PaystackClient } from "../paystack-client"; -import { createPaystackConfig } from "../config"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import * as z from 'zod'; +import { PaystackClient } from '../paystack-client'; +import { createPaystackConfig } from '../config'; export function registerMakePaystackRequestTool(server: McpServer, cliApiKey?: string) { // Create PaystackClient with CLI API key or fallback to environment const config = createPaystackConfig(cliApiKey); const paystackClient = new PaystackClient(config.secretKey); - + server.registerTool( - "make_paystack_request", + 'make_paystack_request', { description: `Make a Paystack API request using the details of the operation. Be sure to get all operation details including method, path path parameters, query parameters, and request body before making a call.`, annotations: { - title: "Make a Paystack API request", + title: 'Make a Paystack API request', }, inputSchema: { request: z.object({ - method: z.string().describe("HTTP method of the API request"), - path: z.string().describe("Path of the API request"), - data: z.looseObject({}).optional().describe("Request data"), - }) - } + method: z.string().describe('HTTP method of the API request'), + path: z.string().describe('Path of the API request'), + data: z.looseObject({}).optional().describe('Request data'), + }), + }, }, async ({ request }) => { try { const response = await paystackClient.makeRequest( request.method, request.path, - request.data - ) + request.data, + ); return { content: [ { - type: "text", + type: 'text', text: JSON.stringify(response, null, 2), - mimeType: "application/json", + mimeType: 'application/json', }, - ] - } - } catch(error) { + ], + }; + } catch (error) { // Follow MCP best practices: return isError flag instead of throwing const errorMessage = error instanceof Error ? error.message : String(error); const statusCode = (error as any).statusCode; - + let detailedMessage = `Unable to make request: ${errorMessage}`; if (statusCode) { detailedMessage = `Unable to make request (HTTP ${statusCode}): ${errorMessage}`; @@ -55,13 +55,13 @@ export function registerMakePaystackRequestTool(server: McpServer, cliApiKey?: s return { content: [ { - type: "text", + type: 'text', text: detailedMessage, }, ], - isError: true - } + isError: true, + }; } - } + }, ); } diff --git a/src/types/client.ts b/src/types/client.ts index 41e5510..4a3e50e 100644 --- a/src/types/client.ts +++ b/src/types/client.ts @@ -17,7 +17,7 @@ export interface PaystackError { message: string; meta?: { nextStep?: string; - }, + }; type?: string; code?: string; -} \ No newline at end of file +} diff --git a/src/types/index.ts b/src/types/index.ts index f9d3852..3c47df3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,2 +1,2 @@ -export * as Oas from "./openapi-components"; -export * from "./client"; \ No newline at end of file +export * as Oas from './openapi-components'; +export * from './client'; diff --git a/src/types/openapi-components.ts b/src/types/openapi-components.ts index fa268c5..1472418 100644 --- a/src/types/openapi-components.ts +++ b/src/types/openapi-components.ts @@ -1,5 +1,4 @@ -import { OpenAPIV3 } from "openapi-types"; - +import { OpenAPIV3 } from 'openapi-types'; export interface Operation { // tag: string; @@ -8,56 +7,56 @@ export interface Operation { method: OpenAPIV3.HttpMethods; description: string; // operationId: string; - queryParameter: EndpointParam[] - pathParameter: EndpointParam[] + queryParameter: EndpointParam[]; + pathParameter: EndpointParam[]; requestBody: Body; // requestBody: OpenAPIV3.ReferenceObject | OpenAPIV3.RequestBodyObject; // responses: OpenAPIV3.ResponsesObject; } export type EndpointParam = { - name: string - description: string - required: boolean - schema: OpenAPIV3.SchemaObject - example: any -} + name: string; + description: string; + required: boolean; + schema: OpenAPIV3.SchemaObject; + example: any; +}; export type BodyParam = { - name: string - type: string - description: string - items?: OpenAPIV3.SchemaObject - required?: boolean - example?: any - children?: BodyParam[] -} + name: string; + type: string; + description: string; + items?: OpenAPIV3.SchemaObject; + required?: boolean; + example?: any; + children?: BodyParam[]; +}; export type Body = { - properties: BodyParam[] - examples: Map -} + properties: BodyParam[]; + examples: Map; +}; export type RequestParameter = { // header: EndpointParam[] - queryParameter: EndpointParam[] - pathParameter: EndpointParam[] -} + queryParameter: EndpointParam[]; + pathParameter: EndpointParam[]; +}; export type BaseEndpoint = { - id: string - name: string - description: string - path: string - method: OpenAPIV3.HttpMethods - body: Body -} + id: string; + name: string; + description: string; + path: string; + method: OpenAPIV3.HttpMethods; + body: Body; +}; -export type Endpoint = BaseEndpoint & RequestParameter +export type Endpoint = BaseEndpoint & RequestParameter; export type PathsOperations = Record>; export type PropertySchema = OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject; // export type OperationDetails = { // path: string; // method: HttpMethod; -// } \ No newline at end of file +// } diff --git a/test/make-paystack-request-tool.spec.ts b/test/make-paystack-request-tool.spec.ts index 536fdb7..1992330 100644 --- a/test/make-paystack-request-tool.spec.ts +++ b/test/make-paystack-request-tool.spec.ts @@ -1,9 +1,9 @@ -import assert from "node:assert"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { registerMakePaystackRequestTool } from "../src/tools/make-paystack-request.js"; +import assert from 'node:assert'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { registerMakePaystackRequestTool } from '../src/tools/make-paystack-request.js'; -describe("MakePaystackRequestTool", () => { - describe("Error handling with isError flag", () => { +describe('MakePaystackRequestTool', () => { + describe('Error handling with isError flag', () => { let server: McpServer; let toolHandler: any; @@ -11,58 +11,58 @@ describe("MakePaystackRequestTool", () => { // Create a mock MCP server server = { registerTool: (name: string, config: any, handler: any) => { - if (name === "make_paystack_request") { + if (name === 'make_paystack_request') { toolHandler = handler; } - } + }, } as any; - // Pass a test API key to avoid environment variable requirement - registerMakePaystackRequestTool(server, "sk_test_1234567890abcdef1234567890abcdef12345678"); + // Pass a test API key to avoid environment variable requirement + registerMakePaystackRequestTool(server, 'sk_test_1234567890abcdef1234567890abcdef12345678'); }); - it("should return isError: true for non-JSON responses", async () => { + it('should return isError: true for non-JSON responses', async () => { // Mock fetch to return HTML error page const originalFetch = global.fetch; global.fetch = async () => { return { status: 502, - text: async () => "

502 Bad Gateway

", + text: async () => '

502 Bad Gateway

', } as Response; }; try { const result = await toolHandler({ request: { - method: "GET", - path: "/test-endpoint", - } + method: 'GET', + path: '/test-endpoint', + }, }); // Verify isError flag is set assert.strictEqual(result.isError, true); - + // Verify error message content assert.ok(result.content); assert.strictEqual(result.content.length, 1); - assert.strictEqual(result.content[0].type, "text"); - assert.ok(result.content[0].text.includes("Unable to make request")); - assert.ok(result.content[0].text.includes("HTTP 502")); - assert.ok(result.content[0].text.includes("non-JSON response")); + assert.strictEqual(result.content[0].type, 'text'); + assert.ok(result.content[0].text.includes('Unable to make request')); + assert.ok(result.content[0].text.includes('HTTP 502')); + assert.ok(result.content[0].text.includes('non-JSON response')); } finally { global.fetch = originalFetch; } }); - it("should omit isError for successful responses", async () => { + it('should omit isError for successful responses', async () => { // Mock fetch to return valid JSON const originalFetch = global.fetch; const validJsonResponse = { status: true, - message: "Success", - data: { id: 123 } + message: 'Success', + data: { id: 123 }, }; - + global.fetch = async () => { return { status: 200, @@ -73,80 +73,80 @@ describe("MakePaystackRequestTool", () => { try { const result = await toolHandler({ request: { - method: "GET", - path: "/test-endpoint", - } + method: 'GET', + path: '/test-endpoint', + }, }); // Verify isError is not set (or false) for successful responses assert.ok(!result.isError); - + // Verify success content assert.ok(result.content); assert.strictEqual(result.content.length, 1); - assert.strictEqual(result.content[0].type, "text"); - assert.strictEqual(result.content[0].mimeType, "application/json"); - + assert.strictEqual(result.content[0].type, 'text'); + assert.strictEqual(result.content[0].mimeType, 'application/json'); + // Parse and verify the response data const parsedResponse = JSON.parse(result.content[0].text); assert.strictEqual(parsedResponse.status, true); - assert.strictEqual(parsedResponse.message, "Success"); + assert.strictEqual(parsedResponse.message, 'Success'); } finally { global.fetch = originalFetch; } }); - it("should include HTTP status code in error message", async () => { + it('should include HTTP status code in error message', async () => { // Mock fetch to return a 504 Gateway Timeout const originalFetch = global.fetch; global.fetch = async () => { return { status: 504, - text: async () => "Gateway Timeout", + text: async () => 'Gateway Timeout', } as Response; }; try { const result = await toolHandler({ request: { - method: "POST", - path: "/transaction/initialize", - data: { amount: 1000 } - } + method: 'POST', + path: '/transaction/initialize', + data: { amount: 1000 }, + }, }); // Verify error response structure assert.strictEqual(result.isError, true); - assert.ok(result.content[0].text.includes("HTTP 504")); + assert.ok(result.content[0].text.includes('HTTP 504')); } finally { global.fetch = originalFetch; } }); - it("should handle network errors with isError flag", async () => { + it('should handle network errors with isError flag', async () => { // Mock fetch to simulate network error const originalFetch = global.fetch; global.fetch = async () => { - throw new Error("Network connection failed"); + throw new Error('Network connection failed'); }; try { const result = await toolHandler({ request: { - method: "GET", - path: "/customer/list", - } + method: 'GET', + path: '/customer/list', + }, }); // Verify error is properly handled assert.strictEqual(result.isError, true); - assert.ok(result.content[0].text.includes("Unable to make request")); + assert.ok(result.content[0].text.includes('Unable to make request')); } finally { global.fetch = originalFetch; } }); }); - describe("Missing API Key Validation", () => { + describe('Missing API Key Validation', () => { let server: McpServer; let originalExit: typeof process.exit; let exitCode: number | undefined; @@ -170,7 +170,7 @@ describe("MakePaystackRequestTool", () => { }; server = { - registerTool: (name: string, config: any, handler: any) => { } + registerTool: (_name: string, _config: any, _handler: any) => {}, } as any; }); @@ -180,17 +180,19 @@ describe("MakePaystackRequestTool", () => { delete process.env.PAYSTACK_TEST_SECRET_KEY; }); - it("should fail when no API key provided via CLI or environment", () => { + it('should fail when no API key provided via CLI or environment', () => { // Ensure no environment variable is set delete process.env.PAYSTACK_TEST_SECRET_KEY; try { registerMakePaystackRequestTool(server); // No cliApiKey parameter - assert.fail("Expected registerMakePaystackRequestTool to throw an error"); + assert.fail('Expected registerMakePaystackRequestTool to throw an error'); } catch (error: any) { - assert.ok(error.message.includes("Process would exit with code 1")); + assert.ok(error.message.includes('Process would exit with code 1')); assert.strictEqual(exitCode, 1); - assert.ok(consoleErrors.some(msg => msg.includes("PAYSTACK_TEST_SECRET_KEY is required"))); + assert.ok( + consoleErrors.some((msg) => msg.includes('PAYSTACK_TEST_SECRET_KEY is required')), + ); } }); }); diff --git a/test/openapi-parser.spec.ts b/test/openapi-parser.spec.ts index 88d8493..7006e41 100644 --- a/test/openapi-parser.spec.ts +++ b/test/openapi-parser.spec.ts @@ -1,19 +1,19 @@ -import assert from "node:assert"; -import path from "node:path"; -import { OpenAPIParser} from "../src/openapi-parser.js"; +import assert from 'node:assert'; +import path from 'node:path'; +import { OpenAPIParser } from '../src/openapi-parser.js'; -describe("OpenAPI parsing", () => { - const oasPath = path.join(__dirname, "../", "src/data/paystack.openapi.yaml"); +describe('OpenAPI parsing', () => { + const oasPath = path.join(__dirname, '../', 'src/data/paystack.openapi.yaml'); const openapi = new OpenAPIParser(oasPath); before(async () => { await openapi.parse(); }); - describe("Get operation by ID", () => { - it("should return operation name given the operation ID", () => { - const op = openapi.getOperationById("transaction_partialDebit"); - assert.equal("Partial Debit", op?.name); + describe('Get operation by ID', () => { + it('should return operation name given the operation ID', () => { + const op = openapi.getOperationById('transaction_partialDebit'); + assert.equal('Partial Debit', op?.name); }); - }) -}); \ No newline at end of file + }); +}); diff --git a/test/paystack-client.spec.ts b/test/paystack-client.spec.ts index ce98c8d..6a11c82 100644 --- a/test/paystack-client.spec.ts +++ b/test/paystack-client.spec.ts @@ -1,48 +1,48 @@ -import assert from "node:assert"; -import { createPaystackClient } from "../src/paystack-client.js"; +import assert from 'node:assert'; +import { createPaystackClient } from '../src/paystack-client.js'; -describe("PaystackClient", () => { +describe('PaystackClient', () => { // Use a test API key for the test client - const paystackClient = createPaystackClient("sk_test_1234567890abcdef1234567890abcdef12345678"); - - describe("makeRequest - Non-JSON Response Handling", () => { - it("should throw a descriptive error for HTML error responses", async () => { + const paystackClient = createPaystackClient('sk_test_1234567890abcdef1234567890abcdef12345678'); + + describe('makeRequest - Non-JSON Response Handling', () => { + it('should throw a descriptive error for HTML error responses', async () => { // This test validates that non-JSON responses (like HTML error pages) // are handled gracefully with proper error messages including status code - + // Mock fetch to return an HTML 502 Bad Gateway response const originalFetch = global.fetch; global.fetch = async () => { return { status: 502, - text: async () => "

502 Bad Gateway

", + text: async () => '

502 Bad Gateway

', } as Response; }; try { - await paystackClient.makeRequest("GET", "/test-endpoint"); - assert.fail("Expected makeRequest to throw an error"); + await paystackClient.makeRequest('GET', '/test-endpoint'); + assert.fail('Expected makeRequest to throw an error'); } catch (error: any) { // Verify error message includes status code and response snippet - assert.ok(error.message.includes("Received non-JSON response from server")); - assert.ok(error.message.includes("HTTP 502")); - assert.ok(error.message.includes("")); - + assert.ok(error.message.includes('Received non-JSON response from server')); + assert.ok(error.message.includes('HTTP 502')); + assert.ok(error.message.includes('')); + // Verify statusCode is attached to error assert.strictEqual(error.statusCode, 502); - + // Verify full responseText is available for debugging assert.ok(error.responseText); - assert.ok(error.responseText.includes("502 Bad Gateway")); + assert.ok(error.responseText.includes('502 Bad Gateway')); } finally { global.fetch = originalFetch; } }); - it("should truncate long non-JSON responses to 200 characters", async () => { + it('should truncate long non-JSON responses to 200 characters', async () => { const originalFetch = global.fetch; - const longHtmlResponse = "" + "x".repeat(300) + ""; - + const longHtmlResponse = '' + 'x'.repeat(300) + ''; + global.fetch = async () => { return { status: 500, @@ -51,20 +51,20 @@ describe("PaystackClient", () => { }; try { - await paystackClient.makeRequest("GET", "/test-endpoint"); - assert.fail("Expected makeRequest to throw an error"); + await paystackClient.makeRequest('GET', '/test-endpoint'); + assert.fail('Expected makeRequest to throw an error'); } catch (error: any) { // Verify the error message contains truncated snippet (200 chars + '...') const snippetMatch = error.message.match(/: (.+)$/); assert.ok(snippetMatch); const snippet = snippetMatch[1]; - + // Should end with '...' for truncation assert.ok(snippet.endsWith('...')); - + // Should be 203 characters (200 + '...') assert.ok(snippet.length <= 203); - + // Full response should still be available assert.strictEqual(error.responseText, longHtmlResponse); } finally { @@ -72,10 +72,10 @@ describe("PaystackClient", () => { } }); - it("should not truncate short non-JSON responses", async () => { + it('should not truncate short non-JSON responses', async () => { const originalFetch = global.fetch; - const shortResponse = "Gateway Timeout"; - + const shortResponse = 'Gateway Timeout'; + global.fetch = async () => { return { status: 504, @@ -84,8 +84,8 @@ describe("PaystackClient", () => { }; try { - await paystackClient.makeRequest("GET", "/test-endpoint"); - assert.fail("Expected makeRequest to throw an error"); + await paystackClient.makeRequest('GET', '/test-endpoint'); + assert.fail('Expected makeRequest to throw an error'); } catch (error: any) { // Verify the error message contains full short response assert.ok(error.message.includes(shortResponse)); @@ -96,14 +96,14 @@ describe("PaystackClient", () => { } }); - it("should successfully parse valid JSON responses", async () => { + it('should successfully parse valid JSON responses', async () => { const originalFetch = global.fetch; const validJsonResponse = { status: true, - message: "Success", - data: { id: 123 } + message: 'Success', + data: { id: 123 }, }; - + global.fetch = async () => { return { status: 200, @@ -112,9 +112,9 @@ describe("PaystackClient", () => { }; try { - const response = await paystackClient.makeRequest("GET", "/test-endpoint"); + const response = await paystackClient.makeRequest('GET', '/test-endpoint'); assert.strictEqual(response.status, true); - assert.strictEqual(response.message, "Success"); + assert.strictEqual(response.message, 'Success'); assert.deepStrictEqual(response.data, { id: 123 }); } finally { global.fetch = originalFetch; diff --git a/test/paystack-skill-resource.spec.ts b/test/paystack-skill-resource.spec.ts index fc97316..08916a7 100644 --- a/test/paystack-skill-resource.spec.ts +++ b/test/paystack-skill-resource.spec.ts @@ -1,15 +1,14 @@ -import assert from "node:assert"; -import * as fs from "node:fs"; -import * as path from "node:path"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { registerSkillResource } from "../src/resources/paystack-skill.js"; +import assert from 'node:assert'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { registerSkillResource } from '../src/resources/paystack-skill.js'; const SKILL_CONTENT = fs.readFileSync( - path.join(__dirname, "..", "src", "data", "paystack-skill.md"), - "utf-8" + path.join(__dirname, '..', 'src', 'data', 'paystack-skill.md'), + 'utf-8', ); -describe("PaystackSkillResource", () => { +describe('PaystackSkillResource', () => { let resourceHandler: any; let registeredName: string; let registeredUri: string; @@ -22,107 +21,104 @@ describe("PaystackSkillResource", () => { registeredUri = uri; registeredMetadata = metadata; resourceHandler = handler; - } + }, } as any; registerSkillResource(server, SKILL_CONTENT); }); - describe("Registration", () => { - it("should register with the correct name", () => { - assert.strictEqual(registeredName, "paystack_skill"); + describe('Registration', () => { + it('should register with the correct name', () => { + assert.strictEqual(registeredName, 'paystack_skill'); }); - it("should register with the correct URI", () => { - assert.strictEqual(registeredUri, "paystack://skill"); + it('should register with the correct URI', () => { + assert.strictEqual(registeredUri, 'paystack://skill'); }); - it("should set mimeType to text/markdown", () => { - assert.strictEqual(registeredMetadata.mimeType, "text/markdown"); + it('should set mimeType to text/markdown', () => { + assert.strictEqual(registeredMetadata.mimeType, 'text/markdown'); }); - it("should have a description", () => { + it('should have a description', () => { assert.ok(registeredMetadata.description); assert.ok(registeredMetadata.description.length > 0); }); }); - describe("Content", () => { + describe('Content', () => { let content: string; before(async () => { - const mockUri = new URL("paystack://skill"); + const mockUri = new URL('paystack://skill'); const result = await resourceHandler(mockUri); content = result.contents[0].text; }); - it("should return text/markdown mimeType in response", async () => { - const mockUri = new URL("paystack://skill"); + it('should return text/markdown mimeType in response', async () => { + const mockUri = new URL('paystack://skill'); const result = await resourceHandler(mockUri); - assert.strictEqual(result.contents[0].mimeType, "text/markdown"); + assert.strictEqual(result.contents[0].mimeType, 'text/markdown'); }); - it("should include documentation index section", () => { - assert.ok(content.includes("## Documentation Index")); + it('should include documentation index section', () => { + assert.ok(content.includes('## Documentation Index')); }); - it("should include code snippets section", () => { - assert.ok(content.includes("## Code Snippets")); + it('should include code snippets section', () => { + assert.ok(content.includes('## Code Snippets')); }); - it("should include payment channels by country section", () => { - assert.ok(content.includes("## Payment Channels by Country")); + it('should include payment channels by country section', () => { + assert.ok(content.includes('## Payment Channels by Country')); }); - it("should include links to Paystack docs", () => { - assert.ok(content.includes("https://paystack.com/docs/llms.txt")); + it('should include links to Paystack docs', () => { + assert.ok(content.includes('https://paystack.com/docs/llms.txt')); }); - it("should include snippet repo URL pattern for JS", () => { - assert.ok(content.includes("PaystackOSS/doc-code-snippets")); - assert.ok(content.includes("index.js")); + it('should include snippet repo URL pattern for JS', () => { + assert.ok(content.includes('PaystackOSS/doc-code-snippets')); + assert.ok(content.includes('index.js')); }); - it("should include snippet repo URL pattern for Shell", () => { - assert.ok(content.includes("index.sh")); + it('should include snippet repo URL pattern for Shell', () => { + assert.ok(content.includes('index.sh')); }); - it("should include all supported countries", () => { - assert.ok(content.includes("Nigeria")); - assert.ok(content.includes("Ghana")); - assert.ok(content.includes("South Africa")); - assert.ok(content.includes("Kenya")); + it('should include all supported countries', () => { + assert.ok(content.includes('Nigeria')); + assert.ok(content.includes('Ghana')); + assert.ok(content.includes('South Africa')); + assert.ok(content.includes('Kenya')); assert.ok(content.includes("Côte d'Ivoire")); }); }); }); -describe("ServerInstructions", () => { - it("should pass instructions to the McpServer constructor", async () => { +describe('ServerInstructions', () => { + it('should pass instructions to the McpServer constructor', async () => { // Dynamically import server module to verify instructions are set // We check the source directly since McpServer options are private - const fs = await import("node:fs"); - const path = await import("node:path"); - const serverSource = fs.readFileSync( - path.join(__dirname, "../src/server.ts"), - "utf-8" - ); + const fs = await import('node:fs'); + const path = await import('node:path'); + const serverSource = fs.readFileSync(path.join(__dirname, '../src/server.ts'), 'utf-8'); assert.ok( - serverSource.includes("instructions:"), - "server.ts should pass instructions to McpServer" + serverSource.includes('instructions:'), + 'server.ts should pass instructions to McpServer', ); assert.ok( - serverSource.includes("smallest currency unit"), - "instructions should include currency unit rule" + serverSource.includes('smallest currency unit'), + 'instructions should include currency unit rule', ); assert.ok( - serverSource.includes("get_paystack_operation"), - "instructions should reference the operation tool" + serverSource.includes('get_paystack_operation'), + 'instructions should reference the operation tool', ); assert.ok( - serverSource.includes("do not invent"), - "instructions should include anti-hallucination directive" + serverSource.includes('do not invent'), + 'instructions should include anti-hallucination directive', ); }); }); diff --git a/tsconfig.json b/tsconfig.json index f0a352a..193a51d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,6 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, - "include": ["src/**/*", "tests/**/*"], + "include": ["src/**/*"], "exclude": ["node_modules"] } \ No newline at end of file