From 10238c3887e6effe32f31f1ff57de3cc61e29255 Mon Sep 17 00:00:00 2001 From: andrew-paystack Date: Mon, 19 Jan 2026 13:24:38 +0300 Subject: [PATCH 1/5] resource and tool setup --- .env.example | 3 +- .gitignore | 3 + package-lock.json | 535 ++++++++++++++++++++++++++++- package.json | 13 +- readme.md | 38 ++ src/config.ts | 43 +++ src/index.ts | 35 +- src/logger.ts | 175 ++++++++++ src/paystack-client.ts | 88 +++++ src/resources/index.ts | 54 +++ src/resources/list-transactions.ts | 64 ++++ src/resources/types.ts | 22 ++ src/tools/index.ts | 38 ++ src/tools/list-transactions.ts | 59 ++++ src/tools/types.ts | 22 ++ src/types.ts | 23 ++ tsconfig.json | 10 +- 17 files changed, 1208 insertions(+), 17 deletions(-) create mode 100644 readme.md create mode 100644 src/config.ts create mode 100644 src/logger.ts create mode 100644 src/paystack-client.ts create mode 100644 src/resources/index.ts create mode 100644 src/resources/list-transactions.ts create mode 100644 src/resources/types.ts create mode 100644 src/tools/index.ts create mode 100644 src/tools/list-transactions.ts create mode 100644 src/tools/types.ts create mode 100644 src/types.ts diff --git a/.env.example b/.env.example index b7b5f72..afb2127 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,3 @@ PAYSTACK_BASE_URL="https://api.paystack.co" -USER_AGENT="paystack-mcp/1.0" \ No newline at end of file +USER_AGENT="paystack-mcp/1.0" +PAYSTACK_SECRET_KEY="sk_secret_key_here" \ No newline at end of file diff --git a/.gitignore b/.gitignore index b8ea8a0..963bd6b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,9 @@ bower_components # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release +# TypeScript build output +build/ + # Dependency directories node_modules/ jspm_packages/ diff --git a/package-lock.json b/package-lock.json index e297da1..0ab05cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,14 +7,19 @@ "": { "name": "paystack-mcp", "version": "1.0.0", - "license": "MTI", + "license": "MIT", "dependencies": { "@modelcontextprotocol/inspector": "^0.18.0", "@modelcontextprotocol/sdk": "^1.25.2", + "dotenv": "^17.2.3", "zod": "^3.25.76" }, + "bin": { + "paystack": "build/index.js" + }, "devDependencies": { "@types/node": "^25.0.7", + "tsx": "^4.21.0", "typescript": "^5.9.3" } }, @@ -30,6 +35,422 @@ "node": ">=12" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@floating-ui/core": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", @@ -1243,7 +1664,6 @@ "version": "25.0.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.7.tgz", "integrity": "sha512-C/er7DlIZgRJO7WtTdYovjIFzGsz0I95UlMyR9anTb4aCpBSRWe5Jc1/RvLKUfzmOxHPGjSE5+63HgLtndxU4w==", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -1737,6 +2157,17 @@ "node": ">=0.3.1" } }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1796,6 +2227,47 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1841,7 +2313,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -1991,6 +2462,20 @@ "node": ">= 0.8" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2052,6 +2537,18 @@ "node": ">= 0.4" } }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2547,7 +3044,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -2560,7 +3056,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -2665,6 +3160,15 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -3066,6 +3570,25 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -3083,7 +3606,6 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3301,7 +3823,6 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index bdc1e77..7f4ea07 100644 --- a/package.json +++ b/package.json @@ -8,19 +8,24 @@ "paystack": "./build/index.js" }, "scripts": { - "build": "tsc && chmod 755 build/index.js" + "build": "tsc && chmod 755 build/index.js", + "dev": "tsx src/index.ts" }, - "files": ["build"], + "files": [ + "build" + ], "keywords": [], "author": "Andrew-Paystack", "license": "MIT", "dependencies": { + "@modelcontextprotocol/inspector": "^0.18.0", "@modelcontextprotocol/sdk": "^1.25.2", - "zod": "^3.25.76", - "@modelcontextprotocol/inspector": "^0.18.0" + "dotenv": "^17.2.3", + "zod": "^3.25.76" }, "devDependencies": { "@types/node": "^25.0.7", + "tsx": "^4.21.0", "typescript": "^5.9.3" } } diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..4c2974b --- /dev/null +++ b/readme.md @@ -0,0 +1,38 @@ +# Paystack MCP Server + +This project implements a server for Paystack's [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server. + + +## Requirements + +- Node.js (v14+ recommended) +- npm or yarn + +## Setup + +1. Clone the repository: + ``` + git clone https://github.com/yourusername/paystack-mcp-server.git + cd paystack-mcp + ``` + +2. Install dependencies: + ``` + npm install + ``` + +3. Configure environment variables: + - Copy `.env.example` to `.env` and update with your Paystack credentials and server settings. + +4. Start the server: + ``` + npm start + ``` + +## Contributing + +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +## License + +MIT \ No newline at end of file diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..34cc741 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,43 @@ +import dotenv from 'dotenv'; +import { z } from 'zod'; + +// Load environment variables from .env file +dotenv.config(); + +// Define schema for required environment variables +const envSchema = z.object({ + PAYSTACK_SECRET_KEY_TEST: z.string().min(1, 'PAYSTACK_SECRET_KEY_TEST is required'), + NODE_ENV: z.enum(['development', 'production', 'test']).default('development'), + LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'), +}); + +// Validate environment variables +function validateEnv() { + try { + return envSchema.parse({ + PAYSTACK_SECRET_KEY_TEST: process.env.PAYSTACK_SECRET_KEY_TEST, + NODE_ENV: process.env.NODE_ENV || 'development', + LOG_LEVEL: process.env.LOG_LEVEL || 'info', + }); + } catch (error) { + if (error instanceof z.ZodError) { + console.error('Environment validation failed:'); + error.errors.forEach((err) => { + console.error(` - ${err.path.join('.')}: ${err.message}`); + }); + console.error('\nPlease check your .env file and ensure all required variables are set.'); + process.exit(1); + } + throw error; + } +} + +// Export validated configuration +export const config = validateEnv(); + +// Paystack API configuration +export const paystackConfig = { + baseURL: 'https://api.paystack.co', + secretKey: config.PAYSTACK_SECRET_KEY_TEST, + timeout: 30000, // 30 seconds +} as const; diff --git a/src/index.ts b/src/index.ts index b752f31..3516eb6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,40 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { z } from "zod"; - -const PAYSTACK_BASE_URL = process.env.PAYSTACK_BASE_URL || "https://api.paystack.co"; -const USER_AGENT = process.env.USER_AGENT || "paystack-mcp/1.0"; +import { TOOLS } from './tools/index.js'; +import { RESOURCES } from './resources/index.js'; +import 'dotenv/config'; // Create server instance const server = new McpServer({ name: "paystack", version: "1.0.0", + description: "Paystack MCP Server" +}); + +TOOLS.forEach(tool => { + server.registerTool( + tool.definition.name, + { + description: tool.definition.description, + annotations: tool.definition.annotations, + _meta: tool.definition._meta + }, + tool.handler + ); +}); + +RESOURCES.forEach(resource => { + server.registerResource( + resource.definition.name, + resource.definition.uri, + { + description: resource.definition.description, + mimeType: resource.definition.mimeType, + annotations: resource.definition.annotations, + _meta: resource.definition._meta + }, + resource.handler + ); }); async function main() { @@ -17,6 +43,7 @@ async function main() { console.error("Paystack MCP Server running on stdio..."); } + main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..2ebeaf5 --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,175 @@ +import { config } from './config.js'; +// Define log levels +export enum LogLevel { + DEBUG = 'debug', + INFO = 'info', + WARN = 'warn', + ERROR = 'error', +} + +// Map log levels to numeric values for comparison +const logLevelValues: Record = { + [LogLevel.DEBUG]: 0, + [LogLevel.INFO]: 1, + [LogLevel.WARN]: 2, + [LogLevel.ERROR]: 3, +}; + +// Sensitive field patterns to redact +const SENSITIVE_PATTERNS = [ + /authorization/i, + /secret/i, + /token/i, + /api[_-]?key/i, + /bearer/i, + /credential/i, + /secret[_-]?key/i, + /cvv/i, + /number/i, +]; +/** + * Redact sensitive fields in card objects + * Only redacts cvv and number, keeps other fields visible + */ +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)) { + // Only redact cvv and number fields in card object + if (key === 'cvv' || key === 'number') { + redactedCard[key] = '[REDACTED]'; + } else { + // Keep other card fields but recursively redact if they're objects + redactedCard[key] = redactSensitiveData(value); + } + } + return redactedCard; + } + + return card; +} + + +function redactSensitiveData(obj: any): any { + if (obj === null || obj === undefined) { + return obj; + } + + 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]') + .replace(/pk_test_\w+/g, '[REDACTED_PUBLIC_KEY]'); + } + + if (Array.isArray(obj)) { + return obj.map(redactSensitiveData); + } + + if (typeof obj === 'object') { + const redacted: any = {}; + for (const [key, value] of Object.entries(obj)) { + // 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))) { + redacted[key] = '[REDACTED]'; + } else { + redacted[key] = redactSensitiveData(value); + } + } + return redacted; + } + + return obj; +} + +class Logger { + private currentLogLevel: LogLevel; + + constructor() { + this.currentLogLevel = config.LOG_LEVEL as LogLevel; + } + + private shouldLog(level: LogLevel): boolean { + return logLevelValues[level] >= logLevelValues[this.currentLogLevel]; + } + + private formatLog(level: LogLevel, message: string, meta?: any) { + const timestamp = new Date().toISOString(); + const logEntry = { + timestamp, + level, + message, + ...(meta && { meta: redactSensitiveData(meta) }), + }; + + return JSON.stringify(logEntry); + } + + debug(message: string, meta?: any) { + if (this.shouldLog(LogLevel.DEBUG)) { + console.log(this.formatLog(LogLevel.DEBUG, message, meta)); + } + } + + info(message: string, meta?: any) { + if (this.shouldLog(LogLevel.INFO)) { + console.log(this.formatLog(LogLevel.INFO, message, meta)); + } + } + + warn(message: string, meta?: any) { + if (this.shouldLog(LogLevel.WARN)) { + console.warn(this.formatLog(LogLevel.WARN, message, meta)); + } + } + + error(message: string, meta?: any) { + if (this.shouldLog(LogLevel.ERROR)) { + console.error(this.formatLog(LogLevel.ERROR, message, meta)); + } + } + + /** + * Log API request + */ + logRequest(method: string, url: string, data?: any, headers?: any) { + this.debug('API Request', { + method, + url, + data, + headers, + }); + } + + /** + * Log API response + */ + logResponse(method: string, url: string, status: number, data?: any) { + this.debug('API Response', { + method, + url, + status, + data, + }); + } + + /** + * Log tool call + */ + logToolCall(toolName: string, params?: any) { + this.info('Tool called', { + tool: toolName, + params, + }); + } +} + +export const logger = new Logger(); diff --git a/src/paystack-client.ts b/src/paystack-client.ts new file mode 100644 index 0000000..50bf5ba --- /dev/null +++ b/src/paystack-client.ts @@ -0,0 +1,88 @@ +import type { PaystackResponse, PaystackError } from "./types.js"; + +const PAYSTACK_BASE_URL = process.env.PAYSTACK_BASE_URL || 'https://api.paystack.co'; +const USER_AGENT = process.env.USER_AGENT || 'Paystack-MCP-Client'; + +class PaystackClient { + private baseUrl: string; + private secretKey: string; + private userAgent: string; + private timeout: number; + + constructor( + secretKey: string, + baseUrl: string = PAYSTACK_BASE_URL, + userAgent: string = USER_AGENT, + timeout: number = 30000 + ) { + if (!secretKey) { + throw new Error("Paystack secret key is required"); + } + + this.secretKey = secretKey; + this.baseUrl = baseUrl; + this.userAgent = userAgent; + this.timeout = timeout; + } + + async get(endpoint: string, params?: Record): Promise> { + const url = params ? `${endpoint}?${new URLSearchParams(params as Record)}` : endpoint; + return this.makeRequest('GET', url); + } + + async post(endpoint: string, data?: any): Promise> { + return this.makeRequest('POST', endpoint, data); + } + + private async makeRequest( + method: string, + endpoint: string, + data?: any + ): Promise> { + const url = `${this.baseUrl}${endpoint}`; + + const headers: Record = { + 'Authorization': `Bearer ${this.secretKey}`, + 'User-Agent': this.userAgent, + 'Accept': 'application/json', + }; + + const config: RequestInit = { + method: method.toUpperCase(), + headers: headers + }; + + // Add Content-Type and body for requests with data + if (data && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) { + headers['Content-Type'] = 'application/json'; + config.body = JSON.stringify(data); + } + + try { + const response = await fetch(url, config); + + // Parse response + const responseText = await response.text(); + let responseData: PaystackResponse | PaystackError; + + try { + responseData = JSON.parse(responseText); + } catch (parseError) { + throw new Error(`Invalid JSON response: ${responseText}`); + } + 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; + throw timeoutError; + } + throw error; + } + + } + } +export const paystackClient = new PaystackClient( + process.env.PAYSTACK_SECRET_KEY! +); \ No newline at end of file diff --git a/src/resources/index.ts b/src/resources/index.ts new file mode 100644 index 0000000..ecd4470 --- /dev/null +++ b/src/resources/index.ts @@ -0,0 +1,54 @@ +import { ResourceDefinition } from './types.js'; +import { listTransactionsResource } from './list-transactions.js'; + +/** + * Registry of all available resources + * + * Each resource includes: + * - definition: MCP resource schema (uri, name, description, mimeType) + * - handler: async function that fetches the resource content + */ +export const RESOURCES: ResourceDefinition[] = [ + listTransactionsResource, +]; + +/** + * Get resource handler by URI pattern + */ +export function getResourceHandler(uri: string): ResourceDefinition['handler'] | undefined { + + const resource = RESOURCES.find(r => { + // Convert URI template to regex pattern + // Step 1: Replace {params} with capture groups FIRST + let pattern = r.definition.uri.replace(/\{[^}]+\}/g, '(.+)'); + + + pattern = pattern + .replace(/\\/g, '\\\\') // Escape backslashes first + .replace(/\./g, '\\.') // Escape dots + .replace(/\*/g, '\\*') // Escape asterisks + .replace(/\+/g, '\\+') // Escape plus (but not in (.+) since we replace carefully) + .replace(/\?/g, '\\?') // Escape question marks + .replace(/\^/g, '\\^') // Escape carets + .replace(/\$/g, '\\$') // Escape dollar signs + .replace(/\|/g, '\\|') // Escape pipes + .replace(/\[/g, '\\[') // Escape square brackets + .replace(/\]/g, '\\]') // Escape square brackets + .replace(/:/g, '\\:') // Escape colons (from paystack:// scheme) + .replace(/\//g, '\\/'); // Escape forward slashes + + pattern = pattern.replace(/\\\(\\\.\\\+\\\)/g, '(.+)'); + + const regex = new RegExp(`^${pattern}$`); + return regex.test(uri); + }); + + return resource?.handler; +} + +/** + * Get all resource definitions (schemas only, for ListResources) + */ +export function getResourceDefinitions() { + return RESOURCES.map(r => r.definition); +} \ No newline at end of file diff --git a/src/resources/list-transactions.ts b/src/resources/list-transactions.ts new file mode 100644 index 0000000..f7904ee --- /dev/null +++ b/src/resources/list-transactions.ts @@ -0,0 +1,64 @@ +import { ResourceDefinition } from './types.js'; +import { paystackClient } from '../paystack-client.js'; +import { logger } from '../logger.js'; +import { config } from '../config.js'; + +export const listTransactionsResource: ResourceDefinition = { + definition: { + uri: 'paystack://transactions', + name: 'Transactions List', + description: 'Get a list of Paystack transactions. Supports filtering by status (success, failed, abandoned) and pagination. URI patterns: paystack://transactions, paystack://transactions/status/{status}, paystack://transactions/page/{page}', + mimeType: 'application/json', + }, + + handler: async (uri: URL) => { + // Convert URL to string for pattern matching + const uriString = uri.toString(); + + // Parse URI to extract optional filters + const params: Record = { + perPage: 50, + }; + + // Extract status filter if present + const statusMatch = uriString.match(/\/status\/(\w+)/); + if (statusMatch) { + params.status = statusMatch[1]; + } + + // Extract page number if present + const pageMatch = uriString.match(/\/page\/(\d+)/); + if (pageMatch) { + params.page = parseInt(pageMatch[1], 10); + } + + logger.info('Fetching transactions list resource', { + uri: uriString, + params, + environment: config.NODE_ENV, + }); + + // Fetch transactions data using shared client + const response = await paystackClient.get('/transaction', params); + + const transactionCount = response.data?.data?.length || 0; + + logger.info('Transactions list resource fetched', { + uri: uriString, + count: transactionCount, + status: params.status || 'all', + page: params.page || 1, + }); + + // Return resource content + return { + contents: [ + { + uri: uriString, + mimeType: 'application/json', + text: JSON.stringify(response.data, null, 2), + }, + ], + }; + }, +}; diff --git a/src/resources/types.ts b/src/resources/types.ts new file mode 100644 index 0000000..9d3c109 --- /dev/null +++ b/src/resources/types.ts @@ -0,0 +1,22 @@ +import { Resource, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js'; + +/** + * Resource content result + * Using the MCP SDK's ReadResourceResult type + */ +export type ResourceContent = ReadResourceResult; + +/** + * Resource handler function signature + */ +export type ResourceHandler = (uri: URL) => Promise; + +/** + * Complete resource definition including schema and handler + */ +export interface ResourceDefinition { + /** Resource metadata for MCP protocol */ + definition: Resource; + /** Handler function that fetches the resource */ + handler: ResourceHandler; +} \ No newline at end of file diff --git a/src/tools/index.ts b/src/tools/index.ts new file mode 100644 index 0000000..a3f96bf --- /dev/null +++ b/src/tools/index.ts @@ -0,0 +1,38 @@ +/** + * Tool Registry + * + * This module exports all available MCP tools. + * + * To add a new tool: + * 1. Create a new file in src/tools/ (e.g., my-tool.ts) + * 2. Export a ToolDefinition with 'definition' and 'handler' + * 3. Import and add it to the TOOLS array below + */ + +import { ToolDefinition } from './types.js'; +import { listTransactions } from './list-transactions.js'; + + +/** + * Registry of all available tools + * + * Each tool includes: + * - definition: MCP tool schema (name, description, inputSchema) + * - handler: async function that executes the tool logic + */ +export const TOOLS: ToolDefinition[] = [listTransactions]; + +/** + * Get tool handler by name + */ +export function getToolHandler(name: string): ToolDefinition['handler'] | undefined { + const tool = TOOLS.find(t => t.definition.name === name); + return tool?.handler; +} + +/** + * Get all tool definitions (schemas only, for ListTools) + */ +export function getToolDefinitions() { + return TOOLS.map(t => t.definition); +} diff --git a/src/tools/list-transactions.ts b/src/tools/list-transactions.ts new file mode 100644 index 0000000..37abf10 --- /dev/null +++ b/src/tools/list-transactions.ts @@ -0,0 +1,59 @@ +import { ToolDefinition } from './types.js'; +import { paystackClient } from '../paystack-client.js'; +import { logger } from '../logger.js'; + +/** + * List Paystack transactions with filtering and pagination + */ +export const listTransactions: ToolDefinition = { + definition: { + name: 'list_transactions', + description: 'List all transactions from Paystack. Supports pagination and filtering by status. Returns an array of transactions with details.', + inputSchema: { + type: 'object', + properties: { + perPage: { + type: 'number', + description: 'Number of transactions per page (default: 50, max: 100)', + minimum: 1, + maximum: 100, + }, + page: { + type: 'number', + description: 'Page number to retrieve (default: 1)', + minimum: 1, + }, + status: { + type: 'string', + description: 'Filter by transaction status', + enum: ['success', 'failed', 'abandoned'], + }, + }, + }, + }, + + handler: async (args) => { + const params: Record = {}; + + if (args.perPage) params.perPage = args.perPage; + if (args.page) params.page = args.page; + if (args.status) params.status = args.status; + + logger.info('Listing transactions', { params }); + + const response = await paystackClient.get('/transaction', params); + + logger.info('Transactions retrieved successfully', { + count: response.data?.length || 0, + }); + + return { + content: [ + { + type: 'text', + text: JSON.stringify(response.data, null, 2), + }, + ], + }; + }, +}; diff --git a/src/tools/types.ts b/src/tools/types.ts new file mode 100644 index 0000000..293eb85 --- /dev/null +++ b/src/tools/types.ts @@ -0,0 +1,22 @@ +import { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js'; + +/** + * Tool execution result + * Using the MCP SDK's CallToolResult type + */ +export type ToolResult = CallToolResult; + +/** + * Tool handler function signature + */ +export type ToolHandler = (args: any) => Promise; + +/** + * Complete tool definition including schema and handler + */ +export interface ToolDefinition { + /** Tool metadata for MCP protocol */ + definition: Tool; + /** Handler function that executes the tool */ + handler: ToolHandler; +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..41e5510 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,23 @@ +export interface PaystackResponse { + status: boolean; + message: string; + data: T; + meta?: { + next?: string; + previous?: string; + perPage?: number; + page?: number; + pageCount?: number; + total?: number; + }; +} + +export interface PaystackError { + status: boolean; + message: string; + meta?: { + nextStep?: string; + }, + type?: string; + code?: string; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 28933fb..b410d07 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,15 @@ "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true }, "include": ["src/**/*"], "exclude": ["node_modules"] From 1fa80dd32a8e8943b1892e26482cb39f1110089f Mon Sep 17 00:00:00 2001 From: andrew-paystack Date: Tue, 20 Jan 2026 16:27:52 +0300 Subject: [PATCH 2/5] refactor Paystack Client and update ts config --- .gitignore | 3 - package-lock.json | 327 +++++++++-------------------- package.json | 4 +- src/config.ts | 6 +- src/index.ts | 6 +- src/logger.ts | 10 +- src/paystack-client.ts | 44 ++-- src/resources/list-transactions.ts | 15 +- src/tools/list-transactions.ts | 6 +- tsconfig.json | 2 +- 10 files changed, 153 insertions(+), 270 deletions(-) diff --git a/.gitignore b/.gitignore index 963bd6b..80a4958 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,6 @@ bower_components .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# TypeScript build output build/ # Dependency directories diff --git a/package-lock.json b/package-lock.json index 0ab05cf..bf271ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@modelcontextprotocol/inspector": "^0.18.0", - "@modelcontextprotocol/sdk": "^1.25.2", + "@modelcontextprotocol/sdk": "^1.25.3", "dotenv": "^17.2.3", "zod": "^3.25.76" }, @@ -27,7 +27,6 @@ "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==", - "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -455,7 +454,6 @@ "version": "1.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", - "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.10" } @@ -464,7 +462,6 @@ "version": "1.7.4", "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", - "license": "MIT", "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" @@ -474,7 +471,6 @@ "version": "2.1.6", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", - "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.7.4" }, @@ -486,13 +482,12 @@ "node_modules/@floating-ui/utils": { "version": "0.2.10", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==" }, "node_modules/@hono/node-server": { - "version": "1.19.8", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.8.tgz", - "integrity": "sha512-0/g2lIOPzX8f3vzW1ggQgvG5mjtFBDBHFAzI5SFAi2DzSqS9luJwqg9T6O/gKYLi+inS7eNxBeIFkkghIPvrMA==", + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", "engines": { "node": ">=18.14.1" }, @@ -504,7 +499,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -512,14 +506,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, "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==", - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -529,12 +521,6 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector/-/inspector-0.18.0.tgz", "integrity": "sha512-aBrBDaI8MtvyS9j3TMRgTHZaOwbe/zh2rbIVplIBtxWifaSfvQX9DbnoI3xv9sZjgeFyF/3CwZdfEVTUx2RfBg==", - "license": "MIT", - "workspaces": [ - "client", - "server", - "cli" - ], "dependencies": { "@modelcontextprotocol/inspector-cli": "^0.18.0", "@modelcontextprotocol/inspector-client": "^0.18.0", @@ -559,7 +545,6 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector-cli/-/inspector-cli-0.18.0.tgz", "integrity": "sha512-QMPjKx8zKmX17S1LF2gWuwbYglKexkdgB0HhKZFXzGrQ0MYoKUsIgokMyV48xr4LipaLS3b2v3ut3nV/jhWeSg==", - "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.24.3", "commander": "^13.1.0", @@ -573,7 +558,6 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector-client/-/inspector-client-0.18.0.tgz", "integrity": "sha512-M6A5SN09tYCoTTGwMi5hdQpesX5eHYn3FCAHTWfv1pZ1Cy7h5GjB1LxL5WhbMhXWmFFJ6AnQVGAJj0P0XkVhUg==", - "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.24.3", "@radix-ui/react-checkbox": "^1.1.4", @@ -605,42 +589,10 @@ "mcp-inspector-client": "bin/start.js" } }, - "node_modules/@modelcontextprotocol/inspector-client/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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/@modelcontextprotocol/inspector-client/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==", - "license": "MIT" - }, - "node_modules/@modelcontextprotocol/inspector-client/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==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, "node_modules/@modelcontextprotocol/inspector-server": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/inspector-server/-/inspector-server-0.18.0.tgz", "integrity": "sha512-N7mDwUuj+gB8ZbZ52M4Oqh37qChS8kWJUkc4qL/MMsaQTVshXEOTcyiQ/mLKa17O5uODZQerAnQJWZbZYReBkg==", - "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.24.3", "cors": "^2.8.5", @@ -655,11 +607,12 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz", - "integrity": "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==", + "version": "1.25.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz", + "integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==", + "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.7", + "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", @@ -692,23 +645,48 @@ } } }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", - "license": "MIT" + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==" }, "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==", - "license": "MIT" + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" }, "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, @@ -731,7 +709,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -761,7 +738,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", @@ -787,7 +763,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -805,7 +780,6 @@ "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==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -820,7 +794,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -835,7 +808,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -871,7 +843,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -889,7 +860,6 @@ "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==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -904,7 +874,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -931,7 +900,6 @@ "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==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -946,7 +914,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", @@ -971,7 +938,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", - "license": "MIT", "peerDependencies": { "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" } @@ -980,7 +946,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -998,7 +963,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, @@ -1021,7 +985,6 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.4" }, @@ -1044,7 +1007,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -1081,7 +1043,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -1099,7 +1060,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", - "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", @@ -1131,7 +1091,6 @@ "version": "1.1.9", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", - "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1155,7 +1114,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1179,7 +1137,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" }, @@ -1202,7 +1159,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -1220,7 +1176,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", @@ -1251,7 +1206,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", @@ -1294,7 +1248,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -1312,7 +1265,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -1330,7 +1282,6 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -1359,7 +1310,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", @@ -1389,7 +1339,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", @@ -1423,7 +1372,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", - "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -1457,7 +1405,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -1475,7 +1422,6 @@ "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==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1490,7 +1436,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1509,7 +1454,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -1527,7 +1471,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, @@ -1545,7 +1488,6 @@ "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==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1560,7 +1502,6 @@ "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==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1575,7 +1516,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/rect": "1.1.1" }, @@ -1593,7 +1533,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -1611,7 +1550,6 @@ "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==", - "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, @@ -1633,37 +1571,32 @@ "node_modules/@radix-ui/rect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", - "license": "MIT" + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==" }, "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==", - "license": "MIT" + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==" }, "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==", - "license": "MIT" + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" }, "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==", - "license": "MIT" + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" }, "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==", - "license": "MIT" + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" }, "node_modules/@types/node": { - "version": "25.0.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.7.tgz", - "integrity": "sha512-C/er7DlIZgRJO7WtTdYovjIFzGsz0I95UlMyR9anTb4aCpBSRWe5Jc1/RvLKUfzmOxHPGjSE5+63HgLtndxU4w==", + "version": "25.0.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.9.tgz", + "integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==", "dependencies": { "undici-types": "~7.16.0" } @@ -1684,7 +1617,6 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1696,7 +1628,6 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -1705,14 +1636,14 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { "type": "github", @@ -1735,11 +1666,30 @@ } } }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", "engines": { "node": ">=8" } @@ -1748,7 +1698,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1762,14 +1711,12 @@ "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "license": "MIT" + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, "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==", - "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -1780,8 +1727,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/body-parser": { "version": "2.2.2", @@ -1810,7 +1756,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1820,7 +1765,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -1870,7 +1814,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1886,7 +1829,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1898,7 +1840,6 @@ "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==", - "license": "Apache-2.0", "dependencies": { "clsx": "^2.1.1" }, @@ -1910,7 +1851,6 @@ "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==", - "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1924,7 +1864,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", "engines": { "node": ">=6" } @@ -1933,7 +1872,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", - "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", @@ -1949,7 +1887,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -1960,14 +1897,12 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commander": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "license": "MIT", "engines": { "node": ">=18" } @@ -1975,14 +1910,12 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concurrently": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", - "license": "MIT", "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", @@ -2053,8 +1986,7 @@ "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "license": "MIT" + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -2073,7 +2005,6 @@ "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==", - "license": "MIT", "engines": { "node": ">= 12" } @@ -2098,7 +2029,6 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", - "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -2114,7 +2044,6 @@ "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==", - "license": "MIT", "engines": { "node": ">=18" }, @@ -2126,7 +2055,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "license": "MIT", "engines": { "node": ">=12" }, @@ -2145,14 +2073,12 @@ "node_modules/detect-node-es": { "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==", - "license": "MIT" + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -2189,8 +2115,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/encodeurl": { "version": "2.0.0", @@ -2272,7 +2197,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", "engines": { "node": ">=6" } @@ -2373,8 +2297,7 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "license": "MIT" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-uri": { "version": "3.1.0", @@ -2405,7 +2328,6 @@ "url": "https://paypal.me/jimmywarting" } ], - "license": "MIT", "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" @@ -2438,7 +2360,6 @@ "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", "dependencies": { "fetch-blob": "^3.1.2" }, @@ -2488,7 +2409,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2520,7 +2440,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", "engines": { "node": ">=6" } @@ -2564,7 +2483,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", "engines": { "node": ">=8" } @@ -2651,7 +2569,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -2666,7 +2583,6 @@ "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==", - "license": "MIT", "engines": { "node": ">=8" } @@ -2675,7 +2591,6 @@ "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==", - "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -2698,7 +2613,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -2725,13 +2639,12 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "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==" }, "node_modules/json-schema-typed": { "version": "8.0.2", @@ -2742,7 +2655,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -2754,7 +2666,6 @@ "version": "0.523.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.523.0.tgz", "integrity": "sha512-rUjQoy7egZT9XYVXBK1je9ckBnNp7qzRZOhLQx5RcEp2dCGlXo+mv6vf7Am4LimEcFBJIIZzSGfgTqc9QCrPSw==", - "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -2762,8 +2673,7 @@ "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "license": "ISC" + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, "node_modules/math-intrinsics": { "version": "1.1.0", @@ -2819,7 +2729,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2855,7 +2764,6 @@ "url": "https://paypal.me/jimmywarting" } ], - "license": "MIT", "engines": { "node": ">=10.5.0" } @@ -2864,7 +2772,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", @@ -2920,7 +2827,6 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", - "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -2945,8 +2851,7 @@ "node_modules/path-is-inside": { "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==", - "license": "(WTFPL OR MIT)" + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" }, "node_modules/path-key": { "version": "3.1.1", @@ -2966,9 +2871,9 @@ } }, "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz", + "integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==", "engines": { "node": ">=16.20.0" } @@ -2977,7 +2882,6 @@ "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "license": "MIT", "engines": { "node": ">=6" } @@ -2998,7 +2902,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", "engines": { "node": ">=6" } @@ -3043,7 +2946,6 @@ "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==", - "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -3055,7 +2957,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -3068,7 +2969,6 @@ "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==", - "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", @@ -3093,7 +2993,6 @@ "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==", - "license": "MIT", "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" @@ -3115,7 +3014,6 @@ "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==", - "license": "MIT", "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" @@ -3125,7 +3023,6 @@ "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==", - "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" @@ -3147,7 +3044,6 @@ "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==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3188,7 +3084,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", - "license": "MIT", "engines": { "node": ">=18" }, @@ -3200,7 +3095,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -3214,7 +3108,6 @@ "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } @@ -3248,7 +3141,6 @@ "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==", - "license": "MIT", "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", @@ -3263,7 +3155,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3272,7 +3163,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3281,7 +3171,6 @@ "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==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3290,7 +3179,6 @@ "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==", - "license": "MIT", "dependencies": { "mime-db": "~1.33.0" }, @@ -3301,14 +3189,12 @@ "node_modules/serve-handler/node_modules/path-to-regexp": { "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==", - "license": "MIT" + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==" }, "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==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3359,7 +3245,6 @@ "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3439,7 +3324,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-5.1.2.tgz", "integrity": "sha512-/y7tJKALVZ1lPzeZZB9jYnmtrL7d0N2zkorii5a7r7dhHkWIuLTzZpZzMJLK1dmYRgX/NCc4iarTO3F7BS2c/A==", - "license": "MIT", "dependencies": { "debug": "^4.3.7", "rxjs": "^7.8.1" @@ -3457,7 +3341,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3471,7 +3354,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3483,7 +3365,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3498,7 +3379,6 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" @@ -3516,7 +3396,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "license": "MIT", "bin": { "tree-kill": "cli.js" } @@ -3525,7 +3404,6 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -3567,8 +3445,7 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/tsx": { "version": "4.21.0", @@ -3631,7 +3508,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -3640,7 +3516,6 @@ "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==", - "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -3661,7 +3536,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", - "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" @@ -3682,8 +3556,7 @@ "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "license": "MIT" + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "node_modules/vary": { "version": "1.1.2", @@ -3697,7 +3570,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", "engines": { "node": ">= 8" } @@ -3720,7 +3592,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3742,7 +3613,6 @@ "version": "8.19.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -3763,7 +3633,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", - "license": "MIT", "dependencies": { "is-wsl": "^3.1.0" }, @@ -3778,7 +3647,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", "engines": { "node": ">=10" } @@ -3787,7 +3655,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -3805,7 +3672,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", "engines": { "node": ">=12" } @@ -3814,7 +3680,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "license": "MIT", "engines": { "node": ">=6" } diff --git a/package.json b/package.json index 7f4ea07..42f79d1 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "paystack-mcp", "version": "1.0.0", "description": "", - "main": "index.js", "type": "module", + "main": "index.js", "bin": { "paystack": "./build/index.js" }, @@ -19,7 +19,7 @@ "license": "MIT", "dependencies": { "@modelcontextprotocol/inspector": "^0.18.0", - "@modelcontextprotocol/sdk": "^1.25.2", + "@modelcontextprotocol/sdk": "^1.25.3", "dotenv": "^17.2.3", "zod": "^3.25.76" }, diff --git a/src/config.ts b/src/config.ts index 34cc741..9c7c070 100644 --- a/src/config.ts +++ b/src/config.ts @@ -21,11 +21,7 @@ function validateEnv() { }); } catch (error) { if (error instanceof z.ZodError) { - console.error('Environment validation failed:'); - error.errors.forEach((err) => { - console.error(` - ${err.path.join('.')}: ${err.message}`); - }); - console.error('\nPlease check your .env file and ensure all required variables are set.'); + // Environment validation failed - exit silently process.exit(1); } throw error; diff --git a/src/index.ts b/src/index.ts index 3516eb6..6d6aba2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,12 @@ +#!/usr/bin/env node +import dotenv from 'dotenv'; + +dotenv.config(); + import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { TOOLS } from './tools/index.js'; import { RESOURCES } from './resources/index.js'; -import 'dotenv/config'; // Create server instance const server = new McpServer({ diff --git a/src/logger.ts b/src/logger.ts index 2ebeaf5..a1ba8f6 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -114,24 +114,28 @@ class Logger { } debug(message: string, meta?: any) { + // Disabled for MCP stdio communication if (this.shouldLog(LogLevel.DEBUG)) { - console.log(this.formatLog(LogLevel.DEBUG, message, meta)); + console.error(this.formatLog(LogLevel.DEBUG, message, meta)); } } info(message: string, meta?: any) { + // Disabled for MCP stdio communication if (this.shouldLog(LogLevel.INFO)) { - console.log(this.formatLog(LogLevel.INFO, message, meta)); + console.error(this.formatLog(LogLevel.INFO, message, meta)); } } warn(message: string, meta?: any) { + // Disabled for MCP stdio communication if (this.shouldLog(LogLevel.WARN)) { - console.warn(this.formatLog(LogLevel.WARN, message, meta)); + console.error(this.formatLog(LogLevel.WARN, message, meta)); } } error(message: string, meta?: any) { + // Disabled for MCP stdio communication if (this.shouldLog(LogLevel.ERROR)) { console.error(this.formatLog(LogLevel.ERROR, message, meta)); } diff --git a/src/paystack-client.ts b/src/paystack-client.ts index 50bf5ba..217d3d5 100644 --- a/src/paystack-client.ts +++ b/src/paystack-client.ts @@ -1,4 +1,8 @@ import type { PaystackResponse, PaystackError } from "./types.js"; +import dotenv from 'dotenv'; + +// Load environment variables +dotenv.config(); const PAYSTACK_BASE_URL = process.env.PAYSTACK_BASE_URL || 'https://api.paystack.co'; const USER_AGENT = process.env.USER_AGENT || 'Paystack-MCP-Client'; @@ -24,42 +28,46 @@ class PaystackClient { this.userAgent = userAgent; this.timeout = timeout; } - - async get(endpoint: string, params?: Record): Promise> { - const url = params ? `${endpoint}?${new URLSearchParams(params as Record)}` : endpoint; - return this.makeRequest('GET', url); - } - async post(endpoint: string, data?: any): Promise> { - return this.makeRequest('POST', endpoint, data); - } + /** + * Make an HTTP request to Paystack API + * @param method - HTTP method (GET, POST, PUT, DELETE, etc.) + * @param endpoint - API endpoint path + * @param data - Request body for POST/PUT/PATCH or query params for GET + */ - private async makeRequest( + async makeRequest( method: string, endpoint: string, data?: any ): Promise> { - const url = `${this.baseUrl}${endpoint}`; + let url = `${this.baseUrl}${endpoint}`; + + if (method === 'GET' && data) { + const params = new URLSearchParams(data as Record); + url = `${url}?${params}`; + } + const headers: Record = { 'Authorization': `Bearer ${this.secretKey}`, 'User-Agent': this.userAgent, 'Accept': 'application/json', }; - const config: RequestInit = { - method: method.toUpperCase(), - headers: headers + const options: RequestInit = { + method: method.toUpperCase() }; // Add Content-Type and body for requests with data - if (data && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) { + if (data && ['POST', 'PUT', 'DELETE', 'PATCH'].includes(method.toUpperCase())) { headers['Content-Type'] = 'application/json'; - config.body = JSON.stringify(data); + options.body = JSON.stringify(data); } - + options.headers = headers; + try { - const response = await fetch(url, config); + const response = await fetch(url, options); // Parse response const responseText = await response.text(); @@ -84,5 +92,5 @@ class PaystackClient { } } export const paystackClient = new PaystackClient( - process.env.PAYSTACK_SECRET_KEY! + process.env.PAYSTACK_SECRET_KEY_TEST! ); \ No newline at end of file diff --git a/src/resources/list-transactions.ts b/src/resources/list-transactions.ts index f7904ee..659dd73 100644 --- a/src/resources/list-transactions.ts +++ b/src/resources/list-transactions.ts @@ -12,6 +12,9 @@ export const listTransactionsResource: ResourceDefinition = { }, handler: async (uri: URL) => { + try { + + // Convert URL to string for pattern matching const uriString = uri.toString(); @@ -39,7 +42,7 @@ export const listTransactionsResource: ResourceDefinition = { }); // Fetch transactions data using shared client - const response = await paystackClient.get('/transaction', params); + const response = await paystackClient.makeRequest('GET', '/transaction', params); const transactionCount = response.data?.data?.length || 0; @@ -60,5 +63,15 @@ export const listTransactionsResource: ResourceDefinition = { }, ], }; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + return { + contents: [{ + uri: uri.toString(), + mimeType: 'application/json', + text: JSON.stringify({ error: errorMessage }, null, 2), + }], + }; + } }, }; diff --git a/src/tools/list-transactions.ts b/src/tools/list-transactions.ts index 37abf10..b36a7b1 100644 --- a/src/tools/list-transactions.ts +++ b/src/tools/list-transactions.ts @@ -41,11 +41,7 @@ export const listTransactions: ToolDefinition = { logger.info('Listing transactions', { params }); - const response = await paystackClient.get('/transaction', params); - - logger.info('Transactions retrieved successfully', { - count: response.data?.length || 0, - }); + const response = await paystackClient.makeRequest('GET', '/transaction', params); return { content: [ diff --git a/tsconfig.json b/tsconfig.json index b410d07..8fafdc8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,6 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, - "include": ["src/**/*"], + "include": ["src/**/*", "tests/**/*"], "exclude": ["node_modules"] } \ No newline at end of file From a733a9bd9b2ee9488d4aad225257b882b5c07a0e Mon Sep 17 00:00:00 2001 From: andrew-paystack Date: Tue, 20 Jan 2026 16:42:04 +0300 Subject: [PATCH 3/5] update moduleResolution --- src/index.ts | 4 ++-- tsconfig.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6d6aba2..b4d8382 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,8 +5,8 @@ dotenv.config(); import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { TOOLS } from './tools/index.js'; -import { RESOURCES } from './resources/index.js'; +import { TOOLS } from './tools/index'; +import { RESOURCES } from './resources/index'; // Create server instance const server = new McpServer({ diff --git a/tsconfig.json b/tsconfig.json index 8fafdc8..f0a352a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { "target": "ES2022", - "module": "Node16", - "moduleResolution": "Node16", + "module": "CommonJS", + // "moduleResolution": "Node16", "outDir": "./build", "rootDir": "./src", "strict": true, From 9152980cf156686c3974623df5fc3d0ecd72deaa Mon Sep 17 00:00:00 2001 From: andrew-paystack Date: Fri, 23 Jan 2026 16:01:49 +0300 Subject: [PATCH 4/5] update paystack client and add test key validation --- src/config.ts | 4 +++- src/paystack-client.ts | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/config.ts b/src/config.ts index 9c7c070..3e6fc22 100644 --- a/src/config.ts +++ b/src/config.ts @@ -6,7 +6,9 @@ dotenv.config(); // Define schema for required environment variables const envSchema = z.object({ - PAYSTACK_SECRET_KEY_TEST: z.string().min(1, 'PAYSTACK_SECRET_KEY_TEST is required'), + PAYSTACK_SECRET_KEY_TEST: z.string().min(30, 'PAYSTACK_SECRET_KEY_TEST is required').refine(val => val.startsWith('sk_test_'), { + message: 'PAYSTACK_SECRET_KEY_TEST must begin with "sk_test_. No live keys allowed."', + }), NODE_ENV: z.enum(['development', 'production', 'test']).default('development'), LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'), }); diff --git a/src/paystack-client.ts b/src/paystack-client.ts index 217d3d5..d259bb4 100644 --- a/src/paystack-client.ts +++ b/src/paystack-client.ts @@ -44,11 +44,6 @@ class PaystackClient { let url = `${this.baseUrl}${endpoint}`; - if (method === 'GET' && data) { - const params = new URLSearchParams(data as Record); - url = `${url}?${params}`; - } - const headers: Record = { 'Authorization': `Bearer ${this.secretKey}`, 'User-Agent': this.userAgent, From 0305e43fad0642398affd3a17ef42cdca6c946c3 Mon Sep 17 00:00:00 2001 From: andrew-paystack Date: Fri, 23 Jan 2026 20:24:45 +0300 Subject: [PATCH 5/5] clean up resources and tools folders --- src/logger.ts | 3 +- src/resources/index.ts | 54 --------------------- src/resources/list-transactions.ts | 77 ------------------------------ src/resources/types.ts | 22 --------- src/tools/index.ts | 38 --------------- src/tools/list-transactions.ts | 55 --------------------- src/tools/types.ts | 22 --------- 7 files changed, 1 insertion(+), 270 deletions(-) delete mode 100644 src/resources/index.ts delete mode 100644 src/resources/list-transactions.ts delete mode 100644 src/resources/types.ts delete mode 100644 src/tools/index.ts delete mode 100644 src/tools/list-transactions.ts delete mode 100644 src/tools/types.ts diff --git a/src/logger.ts b/src/logger.ts index a1ba8f6..068035b 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -62,8 +62,7 @@ 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]') - .replace(/pk_test_\w+/g, '[REDACTED_PUBLIC_KEY]'); + .replace(/sk_test_\w+/g, '[REDACTED_SECRET_KEY]'); } if (Array.isArray(obj)) { diff --git a/src/resources/index.ts b/src/resources/index.ts deleted file mode 100644 index ecd4470..0000000 --- a/src/resources/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { ResourceDefinition } from './types.js'; -import { listTransactionsResource } from './list-transactions.js'; - -/** - * Registry of all available resources - * - * Each resource includes: - * - definition: MCP resource schema (uri, name, description, mimeType) - * - handler: async function that fetches the resource content - */ -export const RESOURCES: ResourceDefinition[] = [ - listTransactionsResource, -]; - -/** - * Get resource handler by URI pattern - */ -export function getResourceHandler(uri: string): ResourceDefinition['handler'] | undefined { - - const resource = RESOURCES.find(r => { - // Convert URI template to regex pattern - // Step 1: Replace {params} with capture groups FIRST - let pattern = r.definition.uri.replace(/\{[^}]+\}/g, '(.+)'); - - - pattern = pattern - .replace(/\\/g, '\\\\') // Escape backslashes first - .replace(/\./g, '\\.') // Escape dots - .replace(/\*/g, '\\*') // Escape asterisks - .replace(/\+/g, '\\+') // Escape plus (but not in (.+) since we replace carefully) - .replace(/\?/g, '\\?') // Escape question marks - .replace(/\^/g, '\\^') // Escape carets - .replace(/\$/g, '\\$') // Escape dollar signs - .replace(/\|/g, '\\|') // Escape pipes - .replace(/\[/g, '\\[') // Escape square brackets - .replace(/\]/g, '\\]') // Escape square brackets - .replace(/:/g, '\\:') // Escape colons (from paystack:// scheme) - .replace(/\//g, '\\/'); // Escape forward slashes - - pattern = pattern.replace(/\\\(\\\.\\\+\\\)/g, '(.+)'); - - const regex = new RegExp(`^${pattern}$`); - return regex.test(uri); - }); - - return resource?.handler; -} - -/** - * Get all resource definitions (schemas only, for ListResources) - */ -export function getResourceDefinitions() { - return RESOURCES.map(r => r.definition); -} \ No newline at end of file diff --git a/src/resources/list-transactions.ts b/src/resources/list-transactions.ts deleted file mode 100644 index 659dd73..0000000 --- a/src/resources/list-transactions.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { ResourceDefinition } from './types.js'; -import { paystackClient } from '../paystack-client.js'; -import { logger } from '../logger.js'; -import { config } from '../config.js'; - -export const listTransactionsResource: ResourceDefinition = { - definition: { - uri: 'paystack://transactions', - name: 'Transactions List', - description: 'Get a list of Paystack transactions. Supports filtering by status (success, failed, abandoned) and pagination. URI patterns: paystack://transactions, paystack://transactions/status/{status}, paystack://transactions/page/{page}', - mimeType: 'application/json', - }, - - handler: async (uri: URL) => { - try { - - - // Convert URL to string for pattern matching - const uriString = uri.toString(); - - // Parse URI to extract optional filters - const params: Record = { - perPage: 50, - }; - - // Extract status filter if present - const statusMatch = uriString.match(/\/status\/(\w+)/); - if (statusMatch) { - params.status = statusMatch[1]; - } - - // Extract page number if present - const pageMatch = uriString.match(/\/page\/(\d+)/); - if (pageMatch) { - params.page = parseInt(pageMatch[1], 10); - } - - logger.info('Fetching transactions list resource', { - uri: uriString, - params, - environment: config.NODE_ENV, - }); - - // Fetch transactions data using shared client - const response = await paystackClient.makeRequest('GET', '/transaction', params); - - const transactionCount = response.data?.data?.length || 0; - - logger.info('Transactions list resource fetched', { - uri: uriString, - count: transactionCount, - status: params.status || 'all', - page: params.page || 1, - }); - - // Return resource content - return { - contents: [ - { - uri: uriString, - mimeType: 'application/json', - text: JSON.stringify(response.data, null, 2), - }, - ], - }; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - return { - contents: [{ - uri: uri.toString(), - mimeType: 'application/json', - text: JSON.stringify({ error: errorMessage }, null, 2), - }], - }; - } - }, -}; diff --git a/src/resources/types.ts b/src/resources/types.ts deleted file mode 100644 index 9d3c109..0000000 --- a/src/resources/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Resource, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js'; - -/** - * Resource content result - * Using the MCP SDK's ReadResourceResult type - */ -export type ResourceContent = ReadResourceResult; - -/** - * Resource handler function signature - */ -export type ResourceHandler = (uri: URL) => Promise; - -/** - * Complete resource definition including schema and handler - */ -export interface ResourceDefinition { - /** Resource metadata for MCP protocol */ - definition: Resource; - /** Handler function that fetches the resource */ - handler: ResourceHandler; -} \ No newline at end of file diff --git a/src/tools/index.ts b/src/tools/index.ts deleted file mode 100644 index a3f96bf..0000000 --- a/src/tools/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Tool Registry - * - * This module exports all available MCP tools. - * - * To add a new tool: - * 1. Create a new file in src/tools/ (e.g., my-tool.ts) - * 2. Export a ToolDefinition with 'definition' and 'handler' - * 3. Import and add it to the TOOLS array below - */ - -import { ToolDefinition } from './types.js'; -import { listTransactions } from './list-transactions.js'; - - -/** - * Registry of all available tools - * - * Each tool includes: - * - definition: MCP tool schema (name, description, inputSchema) - * - handler: async function that executes the tool logic - */ -export const TOOLS: ToolDefinition[] = [listTransactions]; - -/** - * Get tool handler by name - */ -export function getToolHandler(name: string): ToolDefinition['handler'] | undefined { - const tool = TOOLS.find(t => t.definition.name === name); - return tool?.handler; -} - -/** - * Get all tool definitions (schemas only, for ListTools) - */ -export function getToolDefinitions() { - return TOOLS.map(t => t.definition); -} diff --git a/src/tools/list-transactions.ts b/src/tools/list-transactions.ts deleted file mode 100644 index b36a7b1..0000000 --- a/src/tools/list-transactions.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { ToolDefinition } from './types.js'; -import { paystackClient } from '../paystack-client.js'; -import { logger } from '../logger.js'; - -/** - * List Paystack transactions with filtering and pagination - */ -export const listTransactions: ToolDefinition = { - definition: { - name: 'list_transactions', - description: 'List all transactions from Paystack. Supports pagination and filtering by status. Returns an array of transactions with details.', - inputSchema: { - type: 'object', - properties: { - perPage: { - type: 'number', - description: 'Number of transactions per page (default: 50, max: 100)', - minimum: 1, - maximum: 100, - }, - page: { - type: 'number', - description: 'Page number to retrieve (default: 1)', - minimum: 1, - }, - status: { - type: 'string', - description: 'Filter by transaction status', - enum: ['success', 'failed', 'abandoned'], - }, - }, - }, - }, - - handler: async (args) => { - const params: Record = {}; - - if (args.perPage) params.perPage = args.perPage; - if (args.page) params.page = args.page; - if (args.status) params.status = args.status; - - logger.info('Listing transactions', { params }); - - const response = await paystackClient.makeRequest('GET', '/transaction', params); - - return { - content: [ - { - type: 'text', - text: JSON.stringify(response.data, null, 2), - }, - ], - }; - }, -}; diff --git a/src/tools/types.ts b/src/tools/types.ts deleted file mode 100644 index 293eb85..0000000 --- a/src/tools/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js'; - -/** - * Tool execution result - * Using the MCP SDK's CallToolResult type - */ -export type ToolResult = CallToolResult; - -/** - * Tool handler function signature - */ -export type ToolHandler = (args: any) => Promise; - -/** - * Complete tool definition including schema and handler - */ -export interface ToolDefinition { - /** Tool metadata for MCP protocol */ - definition: Tool; - /** Handler function that executes the tool */ - handler: ToolHandler; -}