From 51e9d19722673e012ee943b0f4c6d9a20cfa737f Mon Sep 17 00:00:00 2001 From: vobradovich Date: Tue, 31 Mar 2026 21:04:57 +0200 Subject: [PATCH 1/5] wip: sails mcp initial commit --- bun.lock | 1496 ++++++++++++++++++++++ js/mcp-server/package.json | 24 + js/mcp-server/src/idl-loader.ts | 149 +++ js/mcp-server/src/index.ts | 43 + js/mcp-server/src/registry.ts | 48 + js/mcp-server/src/resources.ts | 74 ++ js/mcp-server/src/summarize.ts | 144 +++ js/mcp-server/src/tools/codec-tools.ts | 263 ++++ js/mcp-server/src/tools/header-tools.ts | 215 ++++ js/mcp-server/src/tools/idl-tools.ts | 147 +++ js/mcp-server/src/tools/source-tools.ts | 93 ++ js/mcp-server/src/tools/type-tools.ts | 171 +++ js/mcp-server/src/tools/util-tools.ts | 264 ++++ js/mcp-server/src/wasm-extractor.ts | 125 ++ js/mcp-server/tests/codec-tools.test.ts | 112 ++ js/mcp-server/tests/header-tools.test.ts | 54 + js/mcp-server/tests/idl-tools.test.ts | 90 ++ js/mcp-server/tsconfig.json | 10 + package.json | 5 +- pnpm-lock.yaml | 727 ++++++++++- pnpm-workspace.yaml | 1 + 21 files changed, 4252 insertions(+), 3 deletions(-) create mode 100644 bun.lock create mode 100644 js/mcp-server/package.json create mode 100644 js/mcp-server/src/idl-loader.ts create mode 100644 js/mcp-server/src/index.ts create mode 100644 js/mcp-server/src/registry.ts create mode 100644 js/mcp-server/src/resources.ts create mode 100644 js/mcp-server/src/summarize.ts create mode 100644 js/mcp-server/src/tools/codec-tools.ts create mode 100644 js/mcp-server/src/tools/header-tools.ts create mode 100644 js/mcp-server/src/tools/idl-tools.ts create mode 100644 js/mcp-server/src/tools/source-tools.ts create mode 100644 js/mcp-server/src/tools/type-tools.ts create mode 100644 js/mcp-server/src/tools/util-tools.ts create mode 100644 js/mcp-server/src/wasm-extractor.ts create mode 100644 js/mcp-server/tests/codec-tools.test.ts create mode 100644 js/mcp-server/tests/header-tools.test.ts create mode 100644 js/mcp-server/tests/idl-tools.test.ts create mode 100644 js/mcp-server/tsconfig.json diff --git a/bun.lock b/bun.lock new file mode 100644 index 000000000..b14e39c12 --- /dev/null +++ b/bun.lock @@ -0,0 +1,1496 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "sails", + "devDependencies": { + "@eslint/js": "^9.39.1", + "@jest/types": "^30.2.0", + "@rollup/plugin-commonjs": "^29.0.0", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-typescript": "^12.3.0", + "@types/jest": "^30.0.0", + "@types/node": "^24.10.1", + "babel-jest": "^30.2.0", + "eslint": "^9.39.1", + "eslint-plugin-unicorn": "^62.0.0", + "globals": "^16.5.0", + "jest": "^30.2.0", + "prettier": "^3.6.2", + "rollup": "^4.53.2", + "rollup-plugin-dts": "^6.2.3", + "rollup-plugin-peer-deps-external": "^2.2.4", + "rollup-plugin-typescript2": "^0.36.0", + "ts-jest": "^29.4.5", + "ts-node": "^10.9.2", + "typescript": "^5.9.3", + "typescript-eslint": "^8.46.4", + }, + }, + "js": { + "name": "sails-js", + "version": "0.5.1", + "devDependencies": { + "@gear-js/api": "0.44.2", + "@polkadot/api": "16.4.6", + "@polkadot/keyring": "^13.5.6", + "@polkadot/types": "16.4.6", + "@polkadot/util": "13.5.6", + "@polkadot/wasm-crypto": "^7.5.1", + "@rollup/plugin-commonjs": "^29.0.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@types/node": "^24.10.1", + "jest": "^30.2.0", + "rollup-plugin-dts": "^6.2.3", + "rollup-plugin-typescript2": "^0.36.0", + "sails-js-parser": "workspace:*", + "sails-js-parser-idl-v2": "workspace:*", + "sails-js-types": "workspace:*", + "sails-js-util": "workspace:*", + "ts-jest": "^29.4.5", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + }, + "peerDependencies": { + "@gear-js/api": "^0.44.1", + "@polkadot/api": "^16.4.1", + "@polkadot/util": "^13.5.1", + }, + }, + "js/cli": { + "name": "sails-js-cli", + "version": "0.5.1", + "bin": { + "sails-js": "./build/app.js", + }, + "devDependencies": { + "@inquirer/prompts": "^7.10.1", + "@types/node": "^24.10.1", + "commander": "^14.0.2", + "inquirer": "^12.11.1", + "jest": "^30.2.0", + "sails-js": "workspace:*", + "sails-js-parser": "workspace:*", + "sails-js-util": "workspace:*", + }, + }, + "js/example": { + "name": "sails-js-example", + "devDependencies": { + "@gear-js/api": "0.44.2", + "@polkadot/api": "16.4.6", + "sails-js": "workspace:*", + "sails-js-cli": "workspace:*", + "typescript": "^5.9.3", + }, + }, + "js/mcp-server": { + "name": "sails-js-mcp-server", + "version": "0.5.1", + "bin": { + "sails-mcp": "./src/index.ts", + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.12.1", + "sails-js": "workspace:*", + "sails-js-parser-idl-v2": "workspace:*", + "sails-js-types": "workspace:*", + "sails-js-util": "workspace:*", + "zod": "^3.24.0", + }, + }, + "js/parser": { + "name": "sails-js-parser", + "version": "0.5.1", + "optionalDependencies": { + "sails-js-types": "workspace:*", + }, + "peerDependencies": { + "sails-js-types": "workspace:*", + }, + }, + "js/parser-idl-v2": { + "name": "sails-js-parser-idl-v2", + "version": "0.5.1", + "dependencies": { + "sails-js-types": "workspace:*", + }, + }, + "js/types": { + "name": "sails-js-types", + "version": "0.5.1", + }, + "js/util": { + "name": "sails-js-util", + "version": "0.5.1", + "devDependencies": { + "sails-js-types": "workspace:*", + }, + }, + }, + "packages": { + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "7.28.5", "js-tokens": "4.0.0", "picocolors": "1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/generator": "7.29.1", "@babel/helper-compilation-targets": "7.28.6", "@babel/helper-module-transforms": "7.28.6", "@babel/helpers": "7.28.6", "@babel/parser": "7.29.0", "@babel/template": "7.28.6", "@babel/traverse": "7.29.0", "@babel/types": "7.29.0", "@jridgewell/remapping": "2.3.5", "convert-source-map": "2.0.0", "debug": "4.4.3", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "7.29.0", "@babel/types": "7.29.0", "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31", "jsesc": "3.1.0" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "7.29.0", "@babel/helper-validator-option": "7.27.1", "browserslist": "4.28.1", "lru-cache": "5.1.1", "semver": "6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "7.28.6", "@babel/helper-validator-identifier": "7.28.5", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "7.28.6", "@babel/types": "7.29.0" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], + + "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], + + "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], + + "@babel/plugin-syntax-bigint": ["@babel/plugin-syntax-bigint@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg=="], + + "@babel/plugin-syntax-class-properties": ["@babel/plugin-syntax-class-properties@7.12.13", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA=="], + + "@babel/plugin-syntax-class-static-block": ["@babel/plugin-syntax-class-static-block@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw=="], + + "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw=="], + + "@babel/plugin-syntax-import-meta": ["@babel/plugin-syntax-import-meta@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g=="], + + "@babel/plugin-syntax-json-strings": ["@babel/plugin-syntax-json-strings@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA=="], + + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], + + "@babel/plugin-syntax-logical-assignment-operators": ["@babel/plugin-syntax-logical-assignment-operators@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig=="], + + "@babel/plugin-syntax-nullish-coalescing-operator": ["@babel/plugin-syntax-nullish-coalescing-operator@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ=="], + + "@babel/plugin-syntax-numeric-separator": ["@babel/plugin-syntax-numeric-separator@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug=="], + + "@babel/plugin-syntax-object-rest-spread": ["@babel/plugin-syntax-object-rest-spread@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA=="], + + "@babel/plugin-syntax-optional-catch-binding": ["@babel/plugin-syntax-optional-catch-binding@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q=="], + + "@babel/plugin-syntax-optional-chaining": ["@babel/plugin-syntax-optional-chaining@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg=="], + + "@babel/plugin-syntax-private-property-in-object": ["@babel/plugin-syntax-private-property-in-object@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg=="], + + "@babel/plugin-syntax-top-level-await": ["@babel/plugin-syntax-top-level-await@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw=="], + + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/parser": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/generator": "7.29.1", "@babel/helper-globals": "7.28.0", "@babel/parser": "7.29.0", "@babel/template": "7.28.6", "@babel/types": "7.29.0", "debug": "4.4.3" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "7.27.1", "@babel/helper-validator-identifier": "7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="], + + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + + "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "2.8.1" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "3.4.3" }, "peerDependencies": { "eslint": "9.39.3" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "2.1.7", "debug": "4.4.3", "minimatch": "3.1.3" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.4", "", { "dependencies": { "ajv": "6.14.0", "debug": "4.4.3", "espree": "10.4.0", "globals": "14.0.0", "ignore": "5.3.2", "import-fresh": "3.3.1", "js-yaml": "4.1.1", "minimatch": "3.1.3", "strip-json-comments": "3.1.1" } }, "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ=="], + + "@eslint/js": ["@eslint/js@9.39.3", "", {}, "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "0.17.0", "levn": "0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@gear-js/api": ["@gear-js/api@0.44.2", "", { "peerDependencies": { "@polkadot/api": "16.4.6", "@polkadot/wasm-crypto": "7.5.4", "rxjs": "7.8.2" } }, "sha512-367E+S5pfgxrTj+QY21qLGu+4CocKAUdbqXyYUVIPBJhkBXLBvcM9iGh6T0jXI2HC7hWncRFtne3DWvd6V6Rng=="], + + "@hono/node-server": ["@hono/node-server@1.19.12", "", { "peerDependencies": { "hono": "^4" } }, "sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "0.19.1", "@humanwhocodes/retry": "0.4.3" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@inquirer/ansi": ["@inquirer/ansi@1.0.2", "", {}, "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ=="], + + "@inquirer/checkbox": ["@inquirer/checkbox@4.3.2", "", { "dependencies": { "@inquirer/ansi": "1.0.2", "@inquirer/core": "10.3.2", "@inquirer/figures": "1.0.15", "@inquirer/type": "3.0.10", "yoctocolors-cjs": "2.1.3" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA=="], + + "@inquirer/confirm": ["@inquirer/confirm@5.1.21", "", { "dependencies": { "@inquirer/core": "10.3.2", "@inquirer/type": "3.0.10" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ=="], + + "@inquirer/core": ["@inquirer/core@10.3.2", "", { "dependencies": { "@inquirer/ansi": "1.0.2", "@inquirer/figures": "1.0.15", "@inquirer/type": "3.0.10", "cli-width": "4.1.0", "mute-stream": "2.0.0", "signal-exit": "4.1.0", "wrap-ansi": "6.2.0", "yoctocolors-cjs": "2.1.3" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A=="], + + "@inquirer/editor": ["@inquirer/editor@4.2.23", "", { "dependencies": { "@inquirer/core": "10.3.2", "@inquirer/external-editor": "1.0.3", "@inquirer/type": "3.0.10" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ=="], + + "@inquirer/expand": ["@inquirer/expand@4.0.23", "", { "dependencies": { "@inquirer/core": "10.3.2", "@inquirer/type": "3.0.10", "yoctocolors-cjs": "2.1.3" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew=="], + + "@inquirer/external-editor": ["@inquirer/external-editor@1.0.3", "", { "dependencies": { "chardet": "2.1.1", "iconv-lite": "0.7.2" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA=="], + + "@inquirer/figures": ["@inquirer/figures@1.0.15", "", {}, "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g=="], + + "@inquirer/input": ["@inquirer/input@4.3.1", "", { "dependencies": { "@inquirer/core": "10.3.2", "@inquirer/type": "3.0.10" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g=="], + + "@inquirer/number": ["@inquirer/number@3.0.23", "", { "dependencies": { "@inquirer/core": "10.3.2", "@inquirer/type": "3.0.10" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg=="], + + "@inquirer/password": ["@inquirer/password@4.0.23", "", { "dependencies": { "@inquirer/ansi": "1.0.2", "@inquirer/core": "10.3.2", "@inquirer/type": "3.0.10" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA=="], + + "@inquirer/prompts": ["@inquirer/prompts@7.10.1", "", { "dependencies": { "@inquirer/checkbox": "4.3.2", "@inquirer/confirm": "5.1.21", "@inquirer/editor": "4.2.23", "@inquirer/expand": "4.0.23", "@inquirer/input": "4.3.1", "@inquirer/number": "3.0.23", "@inquirer/password": "4.0.23", "@inquirer/rawlist": "4.1.11", "@inquirer/search": "3.2.2", "@inquirer/select": "4.4.2" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg=="], + + "@inquirer/rawlist": ["@inquirer/rawlist@4.1.11", "", { "dependencies": { "@inquirer/core": "10.3.2", "@inquirer/type": "3.0.10", "yoctocolors-cjs": "2.1.3" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw=="], + + "@inquirer/search": ["@inquirer/search@3.2.2", "", { "dependencies": { "@inquirer/core": "10.3.2", "@inquirer/figures": "1.0.15", "@inquirer/type": "3.0.10", "yoctocolors-cjs": "2.1.3" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA=="], + + "@inquirer/select": ["@inquirer/select@4.4.2", "", { "dependencies": { "@inquirer/ansi": "1.0.2", "@inquirer/core": "10.3.2", "@inquirer/figures": "1.0.15", "@inquirer/type": "3.0.10", "yoctocolors-cjs": "2.1.3" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w=="], + + "@inquirer/type": ["@inquirer/type@3.0.10", "", { "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA=="], + + "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "5.1.2", "string-width-cjs": "npm:string-width@4.2.3", "strip-ansi": "7.1.2", "strip-ansi-cjs": "npm:strip-ansi@6.0.1", "wrap-ansi": "8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "5.3.1", "find-up": "4.1.0", "get-package-type": "0.1.0", "js-yaml": "3.14.2", "resolve-from": "5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="], + + "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="], + + "@jest/console": ["@jest/console@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "24.10.13", "chalk": "4.1.2", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "slash": "3.0.0" } }, "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ=="], + + "@jest/core": ["@jest/core@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/pattern": "30.0.1", "@jest/reporters": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "24.10.13", "ansi-escapes": "4.3.2", "chalk": "4.1.2", "ci-info": "4.4.0", "exit-x": "0.2.2", "graceful-fs": "4.2.11", "jest-changed-files": "30.2.0", "jest-config": "30.2.0", "jest-haste-map": "30.2.0", "jest-message-util": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-resolve-dependencies": "30.2.0", "jest-runner": "30.2.0", "jest-runtime": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "jest-watcher": "30.2.0", "micromatch": "4.0.8", "pretty-format": "30.2.0", "slash": "3.0.0" } }, "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ=="], + + "@jest/diff-sequences": ["@jest/diff-sequences@30.0.1", "", {}, "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw=="], + + "@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "24.10.13", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "@jest/expect": ["@jest/expect@30.2.0", "", { "dependencies": { "expect": "30.2.0", "jest-snapshot": "30.2.0" } }, "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA=="], + + "@jest/expect-utils": ["@jest/expect-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0" } }, "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA=="], + + "@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "13.0.5", "@types/node": "24.10.13", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "@jest/get-type": ["@jest/get-type@30.1.0", "", {}, "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA=="], + + "@jest/globals": ["@jest/globals@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", "@jest/types": "30.2.0", "jest-mock": "30.2.0" } }, "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw=="], + + "@jest/pattern": ["@jest/pattern@30.0.1", "", { "dependencies": { "@types/node": "24.10.13", "jest-regex-util": "30.0.1" } }, "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA=="], + + "@jest/reporters": ["@jest/reporters@30.2.0", "", { "dependencies": { "@bcoe/v8-coverage": "0.2.3", "@jest/console": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "0.3.31", "@types/node": "24.10.13", "chalk": "4.1.2", "collect-v8-coverage": "1.0.3", "exit-x": "0.2.2", "glob": "10.5.0", "graceful-fs": "4.2.11", "istanbul-lib-coverage": "3.2.2", "istanbul-lib-instrument": "6.0.3", "istanbul-lib-report": "3.0.1", "istanbul-lib-source-maps": "5.0.6", "istanbul-reports": "3.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "jest-worker": "30.2.0", "slash": "3.0.0", "string-length": "4.0.2", "v8-to-istanbul": "9.3.0" } }, "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ=="], + + "@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "0.34.48" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + + "@jest/snapshot-utils": ["@jest/snapshot-utils@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "chalk": "4.1.2", "graceful-fs": "4.2.11", "natural-compare": "1.4.0" } }, "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug=="], + + "@jest/source-map": ["@jest/source-map@30.0.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "callsites": "3.1.0", "graceful-fs": "4.2.11" } }, "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg=="], + + "@jest/test-result": ["@jest/test-result@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/types": "30.2.0", "@types/istanbul-lib-coverage": "2.0.6", "collect-v8-coverage": "1.0.3" } }, "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg=="], + + "@jest/test-sequencer": ["@jest/test-sequencer@30.2.0", "", { "dependencies": { "@jest/test-result": "30.2.0", "graceful-fs": "4.2.11", "jest-haste-map": "30.2.0", "slash": "3.0.0" } }, "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q=="], + + "@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "7.29.0", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "0.3.31", "babel-plugin-istanbul": "7.0.1", "chalk": "4.1.2", "convert-source-map": "2.0.0", "fast-json-stable-stringify": "2.1.0", "graceful-fs": "4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "4.0.8", "pirates": "4.0.7", "slash": "3.0.0", "write-file-atomic": "5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], + + "@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "2.0.6", "@types/istanbul-reports": "3.0.4", "@types/node": "24.10.13", "@types/yargs": "17.0.35", "chalk": "4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "1.8.1", "@emnapi/runtime": "1.8.1", "@tybys/wasm-util": "0.10.1" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], + + "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], + + "@polkadot-api/json-rpc-provider": ["@polkadot-api/json-rpc-provider@0.0.1", "", {}, "sha512-/SMC/l7foRjpykLTUTacIH05H3mr9ip8b5xxfwXlVezXrNVLp3Cv0GX6uItkKd+ZjzVPf3PFrDF2B2/HLSNESA=="], + + "@polkadot-api/json-rpc-provider-proxy": ["@polkadot-api/json-rpc-provider-proxy@0.1.0", "", {}, "sha512-8GSFE5+EF73MCuLQm8tjrbCqlgclcHBSRaswvXziJ0ZW7iw3UEMsKkkKvELayWyBuOPa2T5i1nj6gFOeIsqvrg=="], + + "@polkadot-api/metadata-builders": ["@polkadot-api/metadata-builders@0.3.2", "", { "dependencies": { "@polkadot-api/substrate-bindings": "0.6.0", "@polkadot-api/utils": "0.1.0" } }, "sha512-TKpfoT6vTb+513KDzMBTfCb/ORdgRnsS3TDFpOhAhZ08ikvK+hjHMt5plPiAX/OWkm1Wc9I3+K6W0hX5Ab7MVg=="], + + "@polkadot-api/observable-client": ["@polkadot-api/observable-client@0.3.2", "", { "dependencies": { "@polkadot-api/metadata-builders": "0.3.2", "@polkadot-api/substrate-bindings": "0.6.0", "@polkadot-api/utils": "0.1.0" }, "peerDependencies": { "@polkadot-api/substrate-client": "0.1.4", "rxjs": "7.8.2" } }, "sha512-HGgqWgEutVyOBXoGOPp4+IAq6CNdK/3MfQJmhCJb8YaJiaK4W6aRGrdQuQSTPHfERHCARt9BrOmEvTXAT257Ug=="], + + "@polkadot-api/substrate-bindings": ["@polkadot-api/substrate-bindings@0.6.0", "", { "dependencies": { "@noble/hashes": "1.8.0", "@polkadot-api/utils": "0.1.0", "@scure/base": "1.2.6", "scale-ts": "1.6.1" } }, "sha512-lGuhE74NA1/PqdN7fKFdE5C1gNYX357j1tWzdlPXI0kQ7h3kN0zfxNOpPUN7dIrPcOFZ6C0tRRVrBylXkI6xPw=="], + + "@polkadot-api/substrate-client": ["@polkadot-api/substrate-client@0.1.4", "", { "dependencies": { "@polkadot-api/json-rpc-provider": "0.0.1", "@polkadot-api/utils": "0.1.0" } }, "sha512-MljrPobN0ZWTpn++da9vOvt+Ex+NlqTlr/XT7zi9sqPtDJiQcYl+d29hFAgpaeTqbeQKZwz3WDE9xcEfLE8c5A=="], + + "@polkadot-api/utils": ["@polkadot-api/utils@0.1.0", "", {}, "sha512-MXzWZeuGxKizPx2Xf/47wx9sr/uxKw39bVJUptTJdsaQn/TGq+z310mHzf1RCGvC1diHM8f593KrnDgc9oNbJA=="], + + "@polkadot/api": ["@polkadot/api@16.4.6", "", { "dependencies": { "@polkadot/api-augment": "16.4.6", "@polkadot/api-base": "16.4.6", "@polkadot/api-derive": "16.4.6", "@polkadot/keyring": "13.5.9", "@polkadot/rpc-augment": "16.4.6", "@polkadot/rpc-core": "16.4.6", "@polkadot/rpc-provider": "16.4.6", "@polkadot/types": "16.4.6", "@polkadot/types-augment": "16.4.6", "@polkadot/types-codec": "16.4.6", "@polkadot/types-create": "16.4.6", "@polkadot/types-known": "16.4.6", "@polkadot/util": "13.5.6", "@polkadot/util-crypto": "13.5.9", "eventemitter3": "5.0.4", "rxjs": "7.8.2", "tslib": "2.8.1" } }, "sha512-/RYqejRoAgTR0PJpxRYWgYO7iKMXS/mIhFr7vLKzYNOzEA0nePUHE3iYkrhAj2Rluwy1gPcVoUU8/EYGVsWLGQ=="], + + "@polkadot/api-augment": ["@polkadot/api-augment@16.4.6", "", { "dependencies": { "@polkadot/api-base": "16.4.6", "@polkadot/rpc-augment": "16.4.6", "@polkadot/types": "16.4.6", "@polkadot/types-augment": "16.4.6", "@polkadot/types-codec": "16.4.6", "@polkadot/util": "13.5.6", "tslib": "2.8.1" } }, "sha512-YoNOKNk5dca/32Lu5aaLdafGkkUbMHjKRSzrOUAx48jVUWaQYz0WXps2zfx1zDM2hqIgcmkgCQfMdzwHRnj63w=="], + + "@polkadot/api-base": ["@polkadot/api-base@16.4.6", "", { "dependencies": { "@polkadot/rpc-core": "16.4.6", "@polkadot/types": "16.4.6", "@polkadot/util": "13.5.6", "rxjs": "7.8.2", "tslib": "2.8.1" } }, "sha512-tR7rtNmK+NSqqYLzj0C0OPBqqTMOFiyIxKRj2D3/d1IiS6/pUUo455xdwDPTyuUj7adAinSSUOcTtFOcI5BLOA=="], + + "@polkadot/api-derive": ["@polkadot/api-derive@16.4.6", "", { "dependencies": { "@polkadot/api": "16.4.6", "@polkadot/api-augment": "16.4.6", "@polkadot/api-base": "16.4.6", "@polkadot/rpc-core": "16.4.6", "@polkadot/types": "16.4.6", "@polkadot/types-codec": "16.4.6", "@polkadot/util": "13.5.6", "@polkadot/util-crypto": "13.5.9", "rxjs": "7.8.2", "tslib": "2.8.1" } }, "sha512-kh57AhyLtKU3dM2SLCitMEqUJ3cIjwtLtMpiMB7yNH/OvaE7BZ3VO1TuWoU2+kKgyL8DdX6vhdmM5G9/ni+B3w=="], + + "@polkadot/keyring": ["@polkadot/keyring@13.5.9", "", { "dependencies": { "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6", "@polkadot/util-crypto": "13.5.9" } }, "sha512-bMCpHDN7U8ytxawjBZ89/he5s3AmEZuOdkM/ABcorh/flXNPfyghjFK27Gy4OKoFxX52yJ2sTHR4NxM87GuFXQ=="], + + "@polkadot/networks": ["@polkadot/networks@13.5.9", "", { "dependencies": { "@polkadot/util": "13.5.9", "@substrate/ss58-registry": "1.51.0", "tslib": "2.8.1" } }, "sha512-nmKUKJjiLgcih0MkdlJNMnhEYdwEml2rv/h59ll2+rAvpsVWMTLCb6Cq6q7UC44+8kiWK2UUJMkFU+3PFFxndA=="], + + "@polkadot/rpc-augment": ["@polkadot/rpc-augment@16.4.6", "", { "dependencies": { "@polkadot/rpc-core": "16.4.6", "@polkadot/types": "16.4.6", "@polkadot/types-codec": "16.4.6", "@polkadot/util": "13.5.6", "tslib": "2.8.1" } }, "sha512-Fqx41st3KTCfk831OrAh69ftBzqxklEi5e5S/rB2l5F+OQYAsbGMfTSFWTRRVGgBliWZO+T/Tpw2zJqUwrgn3Q=="], + + "@polkadot/rpc-core": ["@polkadot/rpc-core@16.4.6", "", { "dependencies": { "@polkadot/rpc-augment": "16.4.6", "@polkadot/rpc-provider": "16.4.6", "@polkadot/types": "16.4.6", "@polkadot/util": "13.5.6", "rxjs": "7.8.2", "tslib": "2.8.1" } }, "sha512-xi3VIGRXjebdz0jctZpa7y2A+JaI9LSBdUgkHoUOmGrpNzDpMXoE2xWdxg3M/0hql69mSLhatWS9JvSb5MrBTQ=="], + + "@polkadot/rpc-provider": ["@polkadot/rpc-provider@16.4.6", "", { "dependencies": { "@polkadot/keyring": "13.5.9", "@polkadot/types": "16.4.6", "@polkadot/types-support": "16.4.6", "@polkadot/util": "13.5.6", "@polkadot/util-crypto": "13.5.9", "@polkadot/x-fetch": "13.5.9", "@polkadot/x-global": "13.5.9", "@polkadot/x-ws": "13.5.9", "eventemitter3": "5.0.4", "mock-socket": "9.3.1", "nock": "13.5.6", "tslib": "2.8.1" }, "optionalDependencies": { "@substrate/connect": "0.8.11" } }, "sha512-/ZD1rOWBRoMxnp039pOa8Czpjr/l4+3YYY5OcW9WZj16dRcJK84qVi1m91Hro+Gfe9Dus8VeOD/ncJB+a+haRA=="], + + "@polkadot/types": ["@polkadot/types@16.4.6", "", { "dependencies": { "@polkadot/keyring": "13.5.9", "@polkadot/types-augment": "16.4.6", "@polkadot/types-codec": "16.4.6", "@polkadot/types-create": "16.4.6", "@polkadot/util": "13.5.6", "@polkadot/util-crypto": "13.5.9", "rxjs": "7.8.2", "tslib": "2.8.1" } }, "sha512-vfZSOxs64oy1XOcMY3fAbSCBwqLeWvsUYSOhDkZaaC5zIbKdtimPQgbV1QA2fMli568rehmmpLXpZZtj2CNnmA=="], + + "@polkadot/types-augment": ["@polkadot/types-augment@16.4.6", "", { "dependencies": { "@polkadot/types": "16.4.6", "@polkadot/types-codec": "16.4.6", "@polkadot/util": "13.5.6", "tslib": "2.8.1" } }, "sha512-ZFe6j+HHK+ST4D2MwV7oC4y6pyBMZV1b8ZZT2htTtWf03PE0W2ziQVM+Fg42iSHpgmCyJLSABU11QkGSGtRfyQ=="], + + "@polkadot/types-codec": ["@polkadot/types-codec@16.4.6", "", { "dependencies": { "@polkadot/util": "13.5.6", "@polkadot/x-bigint": "13.5.9", "tslib": "2.8.1" } }, "sha512-KCDDJNPTrScQV1HEMNjBIvtx12/J+DPV/niC+klb39wqeBAt7+wYNd8zSnFQzrLvx+n2eWlJjq0dxQiK+Ljc5A=="], + + "@polkadot/types-create": ["@polkadot/types-create@16.4.6", "", { "dependencies": { "@polkadot/types-codec": "16.4.6", "@polkadot/util": "13.5.6", "tslib": "2.8.1" } }, "sha512-+ABF/SKX+xuCPyKvcHIFNybQYQID7bTfvQPkRhK1QxssMwdVtpYCb6RxYU7gYQhlMBAyEZUwele6/JwT/J5VqA=="], + + "@polkadot/types-known": ["@polkadot/types-known@16.4.6", "", { "dependencies": { "@polkadot/networks": "13.5.9", "@polkadot/types": "16.4.6", "@polkadot/types-codec": "16.4.6", "@polkadot/types-create": "16.4.6", "@polkadot/util": "13.5.6", "tslib": "2.8.1" } }, "sha512-aYCWhn0l+19Vasn32SbXbxf19RX1IHaCizYtSW02FlNKpVlZGfOdqebtpQZUz5TmPIkvk1LGPo+qF0xiJSVlOA=="], + + "@polkadot/types-support": ["@polkadot/types-support@16.4.6", "", { "dependencies": { "@polkadot/util": "13.5.6", "tslib": "2.8.1" } }, "sha512-e83H4MzamzNzxZdxf104xqzsl1YUCF24i2pw19I/6zPVxpt6a9zn4+7VzSVMclaztxxSTITCLbks7/9dLiNhEw=="], + + "@polkadot/util": ["@polkadot/util@13.5.6", "", { "dependencies": { "@polkadot/x-bigint": "13.5.6", "@polkadot/x-global": "13.5.6", "@polkadot/x-textdecoder": "13.5.6", "@polkadot/x-textencoder": "13.5.6", "@types/bn.js": "5.2.0", "bn.js": "5.2.3", "tslib": "2.8.1" } }, "sha512-V+CkW2VdhcMWvl7eXdmlCLGqLxrKvXZtXE76KBbPP5n0Z+8DqQ58IHNOE9xe2LOgqDwIzdLlOUwkyF9Zj19y+Q=="], + + "@polkadot/util-crypto": ["@polkadot/util-crypto@13.5.9", "", { "dependencies": { "@noble/curves": "1.9.7", "@noble/hashes": "1.8.0", "@polkadot/networks": "13.5.9", "@polkadot/wasm-crypto": "7.5.4", "@polkadot/wasm-util": "7.5.4", "@polkadot/x-bigint": "13.5.9", "@polkadot/x-randomvalues": "13.5.9", "@scure/base": "1.2.6", "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6" } }, "sha512-foUesMhxkTk8CZ0/XEcfvHk6I0O+aICqqVJllhOpyp/ZVnrTBKBf59T6RpsXx2pCtBlMsLRvg/6Mw7RND1HqDg=="], + + "@polkadot/wasm-bridge": ["@polkadot/wasm-bridge@7.5.4", "", { "dependencies": { "@polkadot/wasm-util": "7.5.4", "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6", "@polkadot/x-randomvalues": "13.5.9" } }, "sha512-6xaJVvoZbnbgpQYXNw9OHVNWjXmtcoPcWh7hlwx3NpfiLkkjljj99YS+XGZQlq7ks2fVCg7FbfknkNb8PldDaA=="], + + "@polkadot/wasm-crypto": ["@polkadot/wasm-crypto@7.5.4", "", { "dependencies": { "@polkadot/wasm-bridge": "7.5.4", "@polkadot/wasm-crypto-asmjs": "7.5.4", "@polkadot/wasm-crypto-init": "7.5.4", "@polkadot/wasm-crypto-wasm": "7.5.4", "@polkadot/wasm-util": "7.5.4", "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6", "@polkadot/x-randomvalues": "13.5.9" } }, "sha512-1seyClxa7Jd7kQjfnCzTTTfYhTa/KUTDUaD3DMHBk5Q4ZUN1D1unJgX+v1aUeXSPxmzocdZETPJJRZjhVOqg9g=="], + + "@polkadot/wasm-crypto-asmjs": ["@polkadot/wasm-crypto-asmjs@7.5.4", "", { "dependencies": { "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6" } }, "sha512-ZYwxQHAJ8pPt6kYk9XFmyuFuSS+yirJLonvP+DYbxOrARRUHfN4nzp4zcZNXUuaFhpbDobDSFn6gYzye6BUotA=="], + + "@polkadot/wasm-crypto-init": ["@polkadot/wasm-crypto-init@7.5.4", "", { "dependencies": { "@polkadot/wasm-bridge": "7.5.4", "@polkadot/wasm-crypto-asmjs": "7.5.4", "@polkadot/wasm-crypto-wasm": "7.5.4", "@polkadot/wasm-util": "7.5.4", "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6", "@polkadot/x-randomvalues": "13.5.9" } }, "sha512-U6s4Eo2rHs2n1iR01vTz/sOQ7eOnRPjaCsGWhPV+ZC/20hkVzwPAhiizu/IqMEol4tO2yiSheD4D6bn0KxUJhg=="], + + "@polkadot/wasm-crypto-wasm": ["@polkadot/wasm-crypto-wasm@7.5.4", "", { "dependencies": { "@polkadot/wasm-util": "7.5.4", "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6" } }, "sha512-PsHgLsVTu43eprwSvUGnxybtOEuHPES6AbApcs7y5ZbM2PiDMzYbAjNul098xJK/CPtrxZ0ePDFnaQBmIJyTFw=="], + + "@polkadot/wasm-util": ["@polkadot/wasm-util@7.5.4", "", { "dependencies": { "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6" } }, "sha512-hqPpfhCpRAqCIn/CYbBluhh0TXmwkJnDRjxrU9Bnqtw9nMNa97D8JuOjdd2pi0rxm+eeLQ/f1rQMp71RMM9t4w=="], + + "@polkadot/x-bigint": ["@polkadot/x-bigint@13.5.6", "", { "dependencies": { "@polkadot/x-global": "13.5.6", "tslib": "2.8.1" } }, "sha512-HpqZJ9ud94iK/+0Ofacw7QdtvzFp6SucBBml4XwWZTWoLaLOGDsO7FoWE7yCuwPbX8nLgIM6YmQBeUoZmBtVqQ=="], + + "@polkadot/x-fetch": ["@polkadot/x-fetch@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "node-fetch": "3.3.2", "tslib": "2.8.1" } }, "sha512-urwXQZtT4yYROiRdJS6zHu18J/jCoAGpbgPIAjwdqjT11t9XIq4SjuPMxD19xBRhbYe9ocWV8i1KHuoMbZgKbA=="], + + "@polkadot/x-global": ["@polkadot/x-global@13.5.6", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-iw97n0Bnl2284WgAK732LYR4DW6w5+COfBfHzkhiHqs5xwPEwWMgWGrf2hM8WAQqNIz6Ni8w/jagucPyQBur3Q=="], + + "@polkadot/x-randomvalues": ["@polkadot/x-randomvalues@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" }, "peerDependencies": { "@polkadot/util": "13.5.6", "@polkadot/wasm-util": "7.5.4" } }, "sha512-Uuuz3oubf1JCCK97fsnVUnHvk4BGp/W91mQWJlgl5TIOUSSTIRr+lb5GurCfl4kgnQq53Zi5fJV+qR9YumbnZw=="], + + "@polkadot/x-textdecoder": ["@polkadot/x-textdecoder@13.5.6", "", { "dependencies": { "@polkadot/x-global": "13.5.6", "tslib": "2.8.1" } }, "sha512-jTGeYCxFh89KRrP7bNj1CPqKO36Onsi0iA6A+5YtRS5wjdQU+/OFM/EHLTP2nvkvZo/tOkOewMR9sausisUvVQ=="], + + "@polkadot/x-textencoder": ["@polkadot/x-textencoder@13.5.6", "", { "dependencies": { "@polkadot/x-global": "13.5.6", "tslib": "2.8.1" } }, "sha512-iVwz9+OrYCEF9QbNfr9M206mmWvY/AhDmGPfAIeTR4fRgKGVYqcP8RIF8iu/x0MVQWqiVO3vlhlUk7MfrmAnoQ=="], + + "@polkadot/x-ws": ["@polkadot/x-ws@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1", "ws": "8.19.0" } }, "sha512-NKVgvACTIvKT8CjaQu9d0dERkZsWIZngX/4NVSjc01WHmln4F4y/zyBdYn/Z2V0Zw28cISx+lB4qxRmqTe7gbg=="], + + "@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@29.0.0", "", { "dependencies": { "@rollup/pluginutils": "5.3.0", "commondir": "1.0.1", "estree-walker": "2.0.2", "fdir": "6.5.0", "is-reference": "1.2.1", "magic-string": "0.30.21", "picomatch": "4.0.3" }, "optionalDependencies": { "rollup": "4.59.0" } }, "sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ=="], + + "@rollup/plugin-json": ["@rollup/plugin-json@6.1.0", "", { "dependencies": { "@rollup/pluginutils": "5.3.0" }, "optionalDependencies": { "rollup": "4.59.0" } }, "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA=="], + + "@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@16.0.3", "", { "dependencies": { "@rollup/pluginutils": "5.3.0", "@types/resolve": "1.20.2", "deepmerge": "4.3.1", "is-module": "1.0.0", "resolve": "1.22.11" }, "optionalDependencies": { "rollup": "4.59.0" } }, "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg=="], + + "@rollup/plugin-typescript": ["@rollup/plugin-typescript@12.3.0", "", { "dependencies": { "@rollup/pluginutils": "5.3.0", "resolve": "1.22.11" }, "optionalDependencies": { "rollup": "4.59.0", "tslib": "2.8.1" }, "peerDependencies": { "typescript": "5.9.3" } }, "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "1.0.8", "estree-walker": "2.0.2", "picomatch": "4.0.3" }, "optionalDependencies": { "rollup": "4.59.0" } }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="], + + "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], + + "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "@substrate/connect": ["@substrate/connect@0.8.11", "", { "dependencies": { "@substrate/connect-extension-protocol": "2.2.2", "@substrate/connect-known-chains": "1.10.3", "@substrate/light-client-extension-helpers": "1.0.0", "smoldot": "2.0.26" } }, "sha512-ofLs1PAO9AtDdPbdyTYj217Pe+lBfTLltdHDs3ds8no0BseoLeAGxpz1mHfi7zB4IxI3YyAiLjH6U8cw4pj4Nw=="], + + "@substrate/connect-extension-protocol": ["@substrate/connect-extension-protocol@2.2.2", "", {}, "sha512-t66jwrXA0s5Goq82ZtjagLNd7DPGCNjHeehRlE/gcJmJ+G56C0W+2plqOMRicJ8XGR1/YFnUSEqUFiSNbjGrAA=="], + + "@substrate/connect-known-chains": ["@substrate/connect-known-chains@1.10.3", "", {}, "sha512-OJEZO1Pagtb6bNE3wCikc2wrmvEU5x7GxFFLqqbz1AJYYxSlrPCGu4N2og5YTExo4IcloNMQYFRkBGue0BKZ4w=="], + + "@substrate/light-client-extension-helpers": ["@substrate/light-client-extension-helpers@1.0.0", "", { "dependencies": { "@polkadot-api/json-rpc-provider": "0.0.1", "@polkadot-api/json-rpc-provider-proxy": "0.1.0", "@polkadot-api/observable-client": "0.3.2", "@polkadot-api/substrate-client": "0.1.4", "@substrate/connect-extension-protocol": "2.2.2", "@substrate/connect-known-chains": "1.10.3", "rxjs": "7.8.2" }, "peerDependencies": { "smoldot": "2.0.26" } }, "sha512-TdKlni1mBBZptOaeVrKnusMg/UBpWUORNDv5fdCaJklP4RJiFOzBCrzC+CyVI5kQzsXBisZ+2pXm+rIjS38kHg=="], + + "@substrate/ss58-registry": ["@substrate/ss58-registry@1.51.0", "", {}, "sha512-TWDurLiPxndFgKjVavCniytBIw+t4ViOi7TYp9h/D0NMmkEc9klFTo+827eyEJ0lELpqO207Ey7uGxUa+BS1jQ=="], + + "@tsconfig/node10": ["@tsconfig/node10@1.0.12", "", {}, "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ=="], + + "@tsconfig/node12": ["@tsconfig/node12@1.0.11", "", {}, "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="], + + "@tsconfig/node14": ["@tsconfig/node14@1.0.3", "", {}, "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="], + + "@tsconfig/node16": ["@tsconfig/node16@1.0.4", "", {}, "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "7.29.0", "@babel/types": "7.29.0", "@types/babel__generator": "7.27.0", "@types/babel__template": "7.4.4", "@types/babel__traverse": "7.28.0" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + + "@types/bn.js": ["@types/bn.js@5.2.0", "", { "dependencies": { "@types/node": "24.10.13" } }, "sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="], + + "@types/istanbul-lib-report": ["@types/istanbul-lib-report@3.0.3", "", { "dependencies": { "@types/istanbul-lib-coverage": "2.0.6" } }, "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA=="], + + "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "3.0.3" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], + + "@types/jest": ["@types/jest@30.0.0", "", { "dependencies": { "expect": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/node": ["@types/node@24.10.13", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg=="], + + "@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="], + + "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], + + "@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "21.0.3" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], + + "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.56.1", "", { "dependencies": { "@eslint-community/regexpp": "4.12.2", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/type-utils": "8.56.1", "@typescript-eslint/utils": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "7.0.5", "natural-compare": "1.4.0", "ts-api-utils": "2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "8.56.1", "eslint": "9.39.3", "typescript": "5.9.3" } }, "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.56.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "4.4.3" }, "peerDependencies": { "eslint": "9.39.3", "typescript": "5.9.3" } }, "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.56.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "8.56.1", "@typescript-eslint/types": "8.56.1", "debug": "4.4.3" }, "peerDependencies": { "typescript": "5.9.3" } }, "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1" } }, "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.56.1", "", { "peerDependencies": { "typescript": "5.9.3" } }, "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/utils": "8.56.1", "debug": "4.4.3", "ts-api-utils": "2.4.0" }, "peerDependencies": { "eslint": "9.39.3", "typescript": "5.9.3" } }, "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.56.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.56.1", "@typescript-eslint/tsconfig-utils": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "4.4.3", "minimatch": "10.2.2", "semver": "7.7.4", "tinyglobby": "0.2.15", "ts-api-utils": "2.4.0" }, "peerDependencies": { "typescript": "5.9.3" } }, "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.56.1", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1" }, "peerDependencies": { "eslint": "9.39.3", "typescript": "5.9.3" } }, "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "5.0.1" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + + "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], + + "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="], + + "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g=="], + + "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ=="], + + "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.11.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw=="], + + "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw=="], + + "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw=="], + + "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ=="], + + "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w=="], + + "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA=="], + + "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ=="], + + "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew=="], + + "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.11.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg=="], + + "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w=="], + + "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA=="], + + "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.11.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "0.2.12" }, "cpu": "none" }, "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ=="], + + "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw=="], + + "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ=="], + + "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], + + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "8.16.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "acorn-walk": ["acorn-walk@8.3.5", "", { "dependencies": { "acorn": "8.16.0" } }, "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw=="], + + "ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-json-stable-stringify": "2.1.0", "json-schema-traverse": "0.4.1", "uri-js": "4.4.1" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + + "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "3.0.0", "picomatch": "2.3.1" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "babel-jest": ["babel-jest@30.2.0", "", { "dependencies": { "@jest/transform": "30.2.0", "@types/babel__core": "7.20.5", "babel-plugin-istanbul": "7.0.1", "babel-preset-jest": "30.2.0", "chalk": "4.1.2", "graceful-fs": "4.2.11", "slash": "3.0.0" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw=="], + + "babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6", "@istanbuljs/load-nyc-config": "1.1.0", "@istanbuljs/schema": "0.1.3", "istanbul-lib-instrument": "6.0.3", "test-exclude": "6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@30.2.0", "", { "dependencies": { "@types/babel__core": "7.20.5" } }, "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA=="], + + "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "7.8.4", "@babel/plugin-syntax-bigint": "7.8.3", "@babel/plugin-syntax-class-properties": "7.12.13", "@babel/plugin-syntax-class-static-block": "7.14.5", "@babel/plugin-syntax-import-attributes": "7.28.6", "@babel/plugin-syntax-import-meta": "7.10.4", "@babel/plugin-syntax-json-strings": "7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "7.8.3", "@babel/plugin-syntax-numeric-separator": "7.10.4", "@babel/plugin-syntax-object-rest-spread": "7.8.3", "@babel/plugin-syntax-optional-catch-binding": "7.8.3", "@babel/plugin-syntax-optional-chaining": "7.8.3", "@babel/plugin-syntax-private-property-in-object": "7.14.5", "@babel/plugin-syntax-top-level-await": "7.14.5" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="], + + "babel-preset-jest": ["babel-preset-jest@30.2.0", "", { "dependencies": { "babel-plugin-jest-hoist": "30.2.0", "babel-preset-current-node-syntax": "1.2.0" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="], + + "bn.js": ["bn.js@5.2.3", "", {}, "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w=="], + + "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "2.10.0", "caniuse-lite": "1.0.30001774", "electron-to-chromium": "1.5.302", "node-releases": "2.0.27", "update-browserslist-db": "1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], + + "bs-logger": ["bs-logger@0.2.6", "", { "dependencies": { "fast-json-stable-stringify": "2.1.0" } }, "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog=="], + + "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "builtin-modules": ["builtin-modules@5.0.0", "", {}, "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001774", "", {}, "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "4.3.0", "supports-color": "7.2.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "change-case": ["change-case@5.4.4", "", {}, "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w=="], + + "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], + + "chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="], + + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "cjs-module-lexer": ["cjs-module-lexer@2.2.0", "", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="], + + "clean-regexp": ["clean-regexp@1.0.0", "", { "dependencies": { "escape-string-regexp": "1.0.5" } }, "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw=="], + + "cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "4.2.3", "strip-ansi": "6.0.1", "wrap-ansi": "7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="], + + "collect-v8-coverage": ["collect-v8-coverage@1.0.3", "", {}, "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "core-js-compat": ["core-js-compat@3.48.0", "", { "dependencies": { "browserslist": "4.28.1" } }, "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q=="], + + "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], + + "create-require": ["create-require@1.1.1", "", {}, "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "dedent": ["dedent@1.7.1", "", {}, "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "detect-newline": ["detect-newline@3.1.0", "", {}, "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="], + + "diff": ["diff@4.0.4", "", {}, "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.302", "", {}, "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg=="], + + "emittery": ["emittery@0.13.1", "", {}, "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.39.3", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@eslint-community/regexpp": "4.12.2", "@eslint/config-array": "0.21.1", "@eslint/config-helpers": "0.4.2", "@eslint/core": "0.17.0", "@eslint/eslintrc": "3.3.4", "@eslint/js": "9.39.3", "@eslint/plugin-kit": "0.4.1", "@humanfs/node": "0.16.7", "@humanwhocodes/module-importer": "1.0.1", "@humanwhocodes/retry": "0.4.3", "@types/estree": "1.0.8", "ajv": "6.14.0", "chalk": "4.1.2", "cross-spawn": "7.0.6", "debug": "4.4.3", "escape-string-regexp": "4.0.0", "eslint-scope": "8.4.0", "eslint-visitor-keys": "4.2.1", "espree": "10.4.0", "esquery": "1.7.0", "esutils": "2.0.3", "fast-deep-equal": "3.1.3", "file-entry-cache": "8.0.0", "find-up": "5.0.0", "glob-parent": "6.0.2", "ignore": "5.3.2", "imurmurhash": "0.1.4", "is-glob": "4.0.3", "json-stable-stringify-without-jsonify": "1.0.1", "lodash.merge": "4.6.2", "minimatch": "3.1.3", "natural-compare": "1.4.0", "optionator": "0.9.4" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg=="], + + "eslint-plugin-unicorn": ["eslint-plugin-unicorn@62.0.0", "", { "dependencies": { "@babel/helper-validator-identifier": "7.28.5", "@eslint-community/eslint-utils": "4.9.1", "@eslint/plugin-kit": "0.4.1", "change-case": "5.4.4", "ci-info": "4.4.0", "clean-regexp": "1.0.0", "core-js-compat": "3.48.0", "esquery": "1.7.0", "find-up-simple": "1.0.1", "globals": "16.5.0", "indent-string": "5.0.0", "is-builtin-module": "5.0.0", "jsesc": "3.1.0", "pluralize": "8.0.0", "regexp-tree": "0.1.27", "regjsparser": "0.13.0", "semver": "7.7.4", "strip-indent": "4.1.1" }, "peerDependencies": { "eslint": "9.39.3" } }, "sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "4.3.0", "estraverse": "5.3.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "8.16.0", "acorn-jsx": "5.3.2", "eslint-visitor-keys": "4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + + "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], + + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], + + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "7.0.6", "get-stream": "6.0.1", "human-signals": "2.1.0", "is-stream": "2.0.1", "merge-stream": "2.0.0", "npm-run-path": "4.0.1", "onetime": "5.1.2", "signal-exit": "3.0.7", "strip-final-newline": "2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + + "exit-x": ["exit-x@0.2.2", "", {}, "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ=="], + + "expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], + + "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + + "express-rate-limit": ["express-rate-limit@8.3.2", "", { "dependencies": { "ip-address": "10.1.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], + + "fb-watchman": ["fb-watchman@2.0.2", "", { "dependencies": { "bser": "2.1.1" } }, "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA=="], + + "fdir": ["fdir@6.5.0", "", { "optionalDependencies": { "picomatch": "4.0.3" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "3.3.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "4.0.1" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], + + "find-cache-dir": ["find-cache-dir@3.3.2", "", { "dependencies": { "commondir": "1.0.1", "make-dir": "3.1.0", "pkg-dir": "4.2.0" } }, "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "6.0.0", "path-exists": "4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "find-up-simple": ["find-up-simple@1.0.1", "", {}, "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "3.3.3", "keyv": "4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "7.0.6", "signal-exit": "4.1.0" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "3.2.0" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "6.2.0", "universalify": "2.0.1" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-package-type": ["get-package-type@0.1.0", "", {}, "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.4", "minimatch": "3.1.3", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "1.2.8", "neo-async": "2.6.2", "source-map": "0.6.1", "wordwrap": "1.0.0" }, "optionalDependencies": { "uglify-js": "3.19.3" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "hono": ["hono@4.12.9", "", {}, "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA=="], + + "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], + + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": "2.1.2" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "1.0.1", "resolve-from": "4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "import-local": ["import-local@3.2.0", "", { "dependencies": { "pkg-dir": "4.2.0", "resolve-cwd": "3.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "1.4.0", "wrappy": "1.0.2" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "inquirer": ["inquirer@12.11.1", "", { "dependencies": { "@inquirer/ansi": "1.0.2", "@inquirer/core": "10.3.2", "@inquirer/prompts": "7.10.1", "@inquirer/type": "3.0.10", "mute-stream": "2.0.0", "run-async": "4.0.6", "rxjs": "7.8.2" }, "optionalDependencies": { "@types/node": "24.10.13" } }, "sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw=="], + + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-builtin-module": ["is-builtin-module@5.0.0", "", { "dependencies": { "builtin-modules": "5.0.0" } }, "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-generator-fn": ["is-generator-fn@2.1.0", "", {}, "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + + "is-reference": ["is-reference@1.2.1", "", { "dependencies": { "@types/estree": "1.0.8" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], + + "istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/parser": "7.29.0", "@istanbuljs/schema": "0.1.3", "istanbul-lib-coverage": "3.2.2", "semver": "7.7.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "3.2.2", "make-dir": "4.0.0", "supports-color": "7.2.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], + + "istanbul-lib-source-maps": ["istanbul-lib-source-maps@5.0.6", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "debug": "4.4.3", "istanbul-lib-coverage": "3.2.2" } }, "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A=="], + + "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "2.0.2", "istanbul-lib-report": "3.0.1" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="], + + "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "jest": ["jest@30.2.0", "", { "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", "import-local": "3.2.0", "jest-cli": "30.2.0" }, "bin": "./bin/jest.js" }, "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A=="], + + "jest-changed-files": ["jest-changed-files@30.2.0", "", { "dependencies": { "execa": "5.1.1", "jest-util": "30.2.0", "p-limit": "3.1.0" } }, "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ=="], + + "jest-circus": ["jest-circus@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "@types/node": "24.10.13", "chalk": "4.1.2", "co": "4.6.0", "dedent": "1.7.1", "is-generator-fn": "2.1.0", "jest-each": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-runtime": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "p-limit": "3.1.0", "pretty-format": "30.2.0", "pure-rand": "7.0.1", "slash": "3.0.0", "stack-utils": "2.0.6" } }, "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg=="], + + "jest-cli": ["jest-cli@30.2.0", "", { "dependencies": { "@jest/core": "30.2.0", "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "chalk": "4.1.2", "exit-x": "0.2.2", "import-local": "3.2.0", "jest-config": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "yargs": "17.7.2" }, "bin": { "jest": "./bin/jest.js" } }, "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA=="], + + "jest-config": ["jest-config@30.2.0", "", { "dependencies": { "@babel/core": "7.29.0", "@jest/get-type": "30.1.0", "@jest/pattern": "30.0.1", "@jest/test-sequencer": "30.2.0", "@jest/types": "30.2.0", "babel-jest": "30.2.0", "chalk": "4.1.2", "ci-info": "4.4.0", "deepmerge": "4.3.1", "glob": "10.5.0", "graceful-fs": "4.2.11", "jest-circus": "30.2.0", "jest-docblock": "30.2.0", "jest-environment-node": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-runner": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "micromatch": "4.0.8", "parse-json": "5.2.0", "pretty-format": "30.2.0", "slash": "3.0.0", "strip-json-comments": "3.1.1" }, "optionalDependencies": { "@types/node": "24.10.13", "ts-node": "10.9.2" } }, "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA=="], + + "jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "jest-docblock": ["jest-docblock@30.2.0", "", { "dependencies": { "detect-newline": "3.1.0" } }, "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA=="], + + "jest-each": ["jest-each@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "chalk": "4.1.2", "jest-util": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ=="], + + "jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "24.10.13", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="], + + "jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "24.10.13", "anymatch": "3.1.3", "fb-watchman": "2.0.2", "graceful-fs": "4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "4.0.8", "walker": "1.0.8" }, "optionalDependencies": { "fsevents": "2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "jest-leak-detector": ["jest-leak-detector@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "pretty-format": "30.2.0" } }, "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ=="], + + "jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="], + + "jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@jest/types": "30.2.0", "@types/stack-utils": "2.0.3", "chalk": "4.1.2", "graceful-fs": "4.2.11", "micromatch": "4.0.8", "pretty-format": "30.2.0", "slash": "3.0.0", "stack-utils": "2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "24.10.13", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "jest-pnp-resolver": ["jest-pnp-resolver@1.2.3", "", { "optionalDependencies": { "jest-resolve": "30.2.0" } }, "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w=="], + + "jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], + + "jest-resolve": ["jest-resolve@30.2.0", "", { "dependencies": { "chalk": "4.1.2", "graceful-fs": "4.2.11", "jest-haste-map": "30.2.0", "jest-pnp-resolver": "1.2.3", "jest-util": "30.2.0", "jest-validate": "30.2.0", "slash": "3.0.0", "unrs-resolver": "1.11.1" } }, "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A=="], + + "jest-resolve-dependencies": ["jest-resolve-dependencies@30.2.0", "", { "dependencies": { "jest-regex-util": "30.0.1", "jest-snapshot": "30.2.0" } }, "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w=="], + + "jest-runner": ["jest-runner@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/environment": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "24.10.13", "chalk": "4.1.2", "emittery": "0.13.1", "exit-x": "0.2.2", "graceful-fs": "4.2.11", "jest-docblock": "30.2.0", "jest-environment-node": "30.2.0", "jest-haste-map": "30.2.0", "jest-leak-detector": "30.2.0", "jest-message-util": "30.2.0", "jest-resolve": "30.2.0", "jest-runtime": "30.2.0", "jest-util": "30.2.0", "jest-watcher": "30.2.0", "jest-worker": "30.2.0", "p-limit": "3.1.0", "source-map-support": "0.5.13" } }, "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ=="], + + "jest-runtime": ["jest-runtime@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/globals": "30.2.0", "@jest/source-map": "30.0.1", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "24.10.13", "chalk": "4.1.2", "cjs-module-lexer": "2.2.0", "collect-v8-coverage": "1.0.3", "glob": "10.5.0", "graceful-fs": "4.2.11", "jest-haste-map": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "slash": "3.0.0", "strip-bom": "4.0.0" } }, "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg=="], + + "jest-snapshot": ["jest-snapshot@30.2.0", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/generator": "7.29.1", "@babel/plugin-syntax-jsx": "7.28.6", "@babel/plugin-syntax-typescript": "7.28.6", "@babel/types": "7.29.0", "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "@jest/snapshot-utils": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-preset-current-node-syntax": "1.2.0", "chalk": "4.1.2", "expect": "30.2.0", "graceful-fs": "4.2.11", "jest-diff": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "pretty-format": "30.2.0", "semver": "7.7.4", "synckit": "0.11.12" } }, "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA=="], + + "jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "24.10.13", "chalk": "4.1.2", "ci-info": "4.4.0", "graceful-fs": "4.2.11", "picomatch": "4.0.3" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + + "jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "6.3.0", "chalk": "4.1.2", "leven": "3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], + + "jest-watcher": ["jest-watcher@30.2.0", "", { "dependencies": { "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "@types/node": "24.10.13", "ansi-escapes": "4.3.2", "chalk": "4.1.2", "emittery": "0.13.1", "jest-util": "30.2.0", "string-length": "4.0.2" } }, "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg=="], + + "jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "24.10.13", "@ungap/structured-clone": "1.3.0", "jest-util": "30.2.0", "merge-stream": "2.0.0", "supports-color": "8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "jose": ["jose@6.2.2", "", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "2.0.1" }, "optionalDependencies": { "graceful-fs": "4.2.11" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "1.2.1", "type-check": "0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.memoize": ["lodash.memoize@4.1.2", "", {}, "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "3.1.1" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "6.3.1" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "make-error": ["make-error@1.3.6", "", {}, "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="], + + "makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "3.0.3", "picomatch": "2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + + "minimatch": ["minimatch@3.1.3", "", { "dependencies": { "brace-expansion": "1.1.12" } }, "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "mock-socket": ["mock-socket@9.3.1", "", {}, "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "mute-stream": ["mute-stream@2.0.0", "", {}, "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="], + + "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + + "nock": ["nock@13.5.6", "", { "dependencies": { "debug": "4.4.3", "json-stringify-safe": "5.0.1", "propagate": "2.0.1" } }, "sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ=="], + + "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], + + "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "4.0.1", "fetch-blob": "3.2.0", "formdata-polyfill": "4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + + "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], + + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "3.1.1" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1.0.2" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "0.1.4", "fast-levenshtein": "2.0.6", "levn": "0.4.1", "prelude-ls": "1.2.1", "type-check": "0.4.0", "word-wrap": "1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "3.1.0" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "3.1.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "error-ex": "1.3.4", "json-parse-even-better-errors": "2.3.1", "lines-and-columns": "1.2.4" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "10.4.3", "minipass": "7.1.3" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "path-to-regexp": ["path-to-regexp@8.4.1", "", {}, "sha512-fvU78fIjZ+SBM9YwCknCvKOUKkLVqtWDVctl0s7xIqfmfb38t2TT4ZU2gHm+Z8xGwgW+QWEU3oQSAzIbo89Ggw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + + "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "4.1.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], + + "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + + "pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "5.2.0", "react-is": "18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "propagate": ["propagate@2.0.1", "", {}, "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "pure-rand": ["pure-rand@7.0.1", "", {}, "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ=="], + + "qs": ["qs@6.15.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + + "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "regexp-tree": ["regexp-tree@0.1.27", "", { "bin": { "regexp-tree": "bin/regexp-tree" } }, "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA=="], + + "regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "2.16.1", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="], + + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "2.3.3" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], + + "rollup-plugin-dts": ["rollup-plugin-dts@6.3.0", "", { "dependencies": { "magic-string": "0.30.21" }, "optionalDependencies": { "@babel/code-frame": "7.29.0" }, "peerDependencies": { "rollup": "4.59.0", "typescript": "5.9.3" } }, "sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA=="], + + "rollup-plugin-peer-deps-external": ["rollup-plugin-peer-deps-external@2.2.4", "", { "peerDependencies": { "rollup": "4.59.0" } }, "sha512-AWdukIM1+k5JDdAqV/Cxd+nejvno2FVLVeZ74NKggm3Q5s9cbbcOgUPGdbxPi4BXu7xGaZ8HG12F+thImYu/0g=="], + + "rollup-plugin-typescript2": ["rollup-plugin-typescript2@0.36.0", "", { "dependencies": { "@rollup/pluginutils": "4.2.1", "find-cache-dir": "3.3.2", "fs-extra": "10.1.0", "semver": "7.7.4", "tslib": "2.8.1" }, "peerDependencies": { "rollup": "4.59.0", "typescript": "5.9.3" } }, "sha512-NB2CSQDxSe9+Oe2ahZbf+B4bh7pHwjV5L+RSYpCu7Q5ROuN94F9b6ioWwKfz3ueL3KTtmX4o2MUH2cgHDIEUsw=="], + + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "run-async": ["run-async@4.0.6", "", {}, "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ=="], + + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "sails-js": ["sails-js@workspace:js"], + + "sails-js-cli": ["sails-js-cli@workspace:js/cli"], + + "sails-js-example": ["sails-js-example@workspace:js/example"], + + "sails-js-mcp-server": ["sails-js-mcp-server@workspace:js/mcp-server"], + + "sails-js-parser": ["sails-js-parser@workspace:js/parser"], + + "sails-js-parser-idl-v2": ["sails-js-parser-idl-v2@workspace:js/parser-idl-v2"], + + "sails-js-types": ["sails-js-types@workspace:js/types"], + + "sails-js-util": ["sails-js-util@workspace:js/util"], + + "scale-ts": ["scale-ts@1.6.1", "", {}, "sha512-PBMc2AWc6wSEqJYBDPcyCLUj9/tMKnLX70jLOSndMtcUoLQucP/DM0vnQo1wJAYjTrQiq8iG9rD0q6wFzgjH7g=="], + + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + + "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "smoldot": ["smoldot@2.0.26", "", { "dependencies": { "ws": "8.19.0" } }, "sha512-F+qYmH4z2s2FK+CxGj8moYcd1ekSIKH8ywkdqlOz88Dat35iB1DIYL11aILN46YSGMzQW/lbJNS307zBSDN5Ig=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "1.1.2", "source-map": "0.6.1" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="], + + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + + "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], + + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "string-length": ["string-length@4.0.2", "", { "dependencies": { "char-regex": "1.0.2", "strip-ansi": "6.0.1" } }, "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], + + "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + + "strip-indent": ["strip-indent@4.1.1", "", {}, "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="], + + "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "0.1.3", "glob": "7.2.3", "minimatch": "3.1.3" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "6.5.0", "picomatch": "4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "tmpl": ["tmpl@1.0.5", "", {}, "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": "5.9.3" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + + "ts-jest": ["ts-jest@29.4.6", "", { "dependencies": { "bs-logger": "0.2.6", "fast-json-stable-stringify": "2.1.0", "handlebars": "4.7.8", "json5": "2.2.3", "lodash.memoize": "4.1.2", "make-error": "1.3.6", "semver": "7.7.4", "type-fest": "4.41.0", "yargs-parser": "21.1.1" }, "optionalDependencies": { "@babel/core": "7.29.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-jest": "30.2.0", "jest-util": "30.2.0" }, "peerDependencies": { "jest": "30.2.0", "typescript": "5.9.3" }, "bin": { "ts-jest": "cli.js" } }, "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA=="], + + "ts-node": ["ts-node@10.9.2", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "@tsconfig/node10": "1.0.12", "@tsconfig/node12": "1.0.11", "@tsconfig/node14": "1.0.3", "@tsconfig/node16": "1.0.4", "acorn": "8.16.0", "acorn-walk": "8.3.5", "arg": "4.1.3", "create-require": "1.1.1", "diff": "4.0.4", "make-error": "1.3.6", "v8-compile-cache-lib": "3.0.1", "yn": "3.1.1" }, "peerDependencies": { "@types/node": "24.10.13", "typescript": "5.9.3" }, "bin": { "ts-node": "dist/bin.js", "ts-script": "dist/bin-script-deprecated.js", "ts-node-cwd": "dist/bin-cwd.js", "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js" } }, "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], + + "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "typescript-eslint": ["typescript-eslint@8.56.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.56.1", "@typescript-eslint/parser": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/utils": "8.56.1" }, "peerDependencies": { "eslint": "9.39.3", "typescript": "5.9.3" } }, "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ=="], + + "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "0.3.4" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "3.2.0", "picocolors": "1.1.1" }, "peerDependencies": { "browserslist": "4.28.1" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "2.3.1" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "v8-compile-cache-lib": ["v8-compile-cache-lib@3.0.1", "", {}, "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="], + + "v8-to-istanbul": ["v8-to-istanbul@9.3.0", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "@types/istanbul-lib-coverage": "2.0.6", "convert-source-map": "2.0.0" } }, "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], + + "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + + "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + + "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "0.1.4", "signal-exit": "4.1.0" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], + + "ws": ["ws@8.19.0", "", {}, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "8.0.1", "escalade": "3.2.0", "get-caller-file": "2.0.5", "require-directory": "2.1.1", "string-width": "4.2.3", "y18n": "5.0.8", "yargs-parser": "21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], + + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], + + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "0.2.0", "emoji-regex": "9.2.2", "strip-ansi": "7.1.2" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "6.2.2" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "6.2.3", "string-width": "5.1.2", "strip-ansi": "7.1.2" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "@istanbuljs/load-nyc-config/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "5.0.0", "path-exists": "4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "1.0.10", "esprima": "4.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + + "@jest/reporters/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "3.3.1", "jackspeak": "3.4.3", "minimatch": "9.0.6", "minipass": "7.1.3", "package-json-from-dist": "1.0.1", "path-scurry": "1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + + "@modelcontextprotocol/sdk/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], + + "@polkadot/networks/@polkadot/util": ["@polkadot/util@13.5.9", "", { "dependencies": { "@polkadot/x-bigint": "13.5.9", "@polkadot/x-global": "13.5.9", "@polkadot/x-textdecoder": "13.5.9", "@polkadot/x-textencoder": "13.5.9", "@types/bn.js": "5.2.0", "bn.js": "5.2.3", "tslib": "2.8.1" } }, "sha512-pIK3XYXo7DKeFRkEBNYhf3GbCHg6dKQisSvdzZwuyzA6m7YxQq4DFw4IE464ve4Z7WsJFt3a6C9uII36hl9EWw=="], + + "@polkadot/rpc-provider/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + + "@polkadot/types-codec/@polkadot/x-bigint": ["@polkadot/x-bigint@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" } }, "sha512-JVW6vw3e8fkcRyN9eoc6JIl63MRxNQCP/tuLdHWZts1tcAYao0hpWUzteqJY93AgvmQ91KPsC1Kf3iuuZCi74g=="], + + "@polkadot/util-crypto/@polkadot/x-bigint": ["@polkadot/x-bigint@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" } }, "sha512-JVW6vw3e8fkcRyN9eoc6JIl63MRxNQCP/tuLdHWZts1tcAYao0hpWUzteqJY93AgvmQ91KPsC1Kf3iuuZCi74g=="], + + "@polkadot/x-fetch/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + + "@polkadot/x-randomvalues/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + + "@polkadot/x-ws/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.2", "", { "dependencies": { "brace-expansion": "5.0.3" } }, "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw=="], + + "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "ajv-formats/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], + + "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "clean-regexp/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "istanbul-lib-report/make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "7.7.4" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], + + "jest-config/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "3.3.1", "jackspeak": "3.4.3", "minimatch": "9.0.6", "minipass": "7.1.3", "package-json-from-dist": "1.0.1", "path-scurry": "1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + + "jest-runtime/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "3.3.1", "jackspeak": "3.4.3", "minimatch": "9.0.6", "minipass": "7.1.3", "package-json-from-dist": "1.0.1", "path-scurry": "1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + + "jest-validate/camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + + "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "make-dir/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "5.0.0", "path-exists": "4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "rollup-plugin-typescript2/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "2.0.2", "picomatch": "2.3.1" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], + + "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "1.0.3" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + + "@jest/reporters/glob/minimatch": ["minimatch@9.0.6", "", { "dependencies": { "brace-expansion": "5.0.3" } }, "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ=="], + + "@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "@polkadot/networks/@polkadot/util/@polkadot/x-bigint": ["@polkadot/x-bigint@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" } }, "sha512-JVW6vw3e8fkcRyN9eoc6JIl63MRxNQCP/tuLdHWZts1tcAYao0hpWUzteqJY93AgvmQ91KPsC1Kf3iuuZCi74g=="], + + "@polkadot/networks/@polkadot/util/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + + "@polkadot/networks/@polkadot/util/@polkadot/x-textdecoder": ["@polkadot/x-textdecoder@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" } }, "sha512-W2HhVNUbC/tuFdzNMbnXAWsIHSg9SC9QWDNmFD3nXdSzlXNgL8NmuiwN2fkYvCQBtp/XSoy0gDLx0C+Fo19cfw=="], + + "@polkadot/networks/@polkadot/util/@polkadot/x-textencoder": ["@polkadot/x-textencoder@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" } }, "sha512-SG0MHnLUgn1ZxFdm0KzMdTHJ47SfqFhdIPMcGA0Mg/jt2rwrfrP3jtEIJMsHfQpHvfsNPfv55XOMmoPWuQnP/Q=="], + + "@polkadot/types-codec/@polkadot/x-bigint/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + + "@polkadot/util-crypto/@polkadot/x-bigint/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], + + "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "jest-config/glob/minimatch": ["minimatch@9.0.6", "", { "dependencies": { "brace-expansion": "5.0.3" } }, "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ=="], + + "jest-runtime/glob/minimatch": ["minimatch@9.0.6", "", { "dependencies": { "brace-expansion": "5.0.3" } }, "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ=="], + + "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "rollup-plugin-typescript2/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "@jest/reporters/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "jest-config/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], + + "jest-runtime/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], + + "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "@jest/reporters/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "jest-config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "jest-runtime/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + } +} diff --git a/js/mcp-server/package.json b/js/mcp-server/package.json new file mode 100644 index 000000000..b8fa0d406 --- /dev/null +++ b/js/mcp-server/package.json @@ -0,0 +1,24 @@ +{ + "name": "sails-js-mcp-server", + "version": "0.5.1", + "description": "MCP server for Sails IDL & Program development", + "private": true, + "type": "module", + "license": "GPL-3.0", + "author": "Gear Technologies", + "bin": { + "sails-mcp": "./src/index.ts" + }, + "scripts": { + "start": "bun src/index.ts", + "test": "bun test" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.12.1", + "sails-js": "workspace:*", + "sails-js-parser-idl-v2": "workspace:*", + "sails-js-types": "workspace:*", + "sails-js-util": "workspace:*", + "zod": "^3.24.0" + } +} diff --git a/js/mcp-server/src/idl-loader.ts b/js/mcp-server/src/idl-loader.ts new file mode 100644 index 000000000..642c7b9a4 --- /dev/null +++ b/js/mcp-server/src/idl-loader.ts @@ -0,0 +1,149 @@ +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; + +interface IdlSource { + content: string; + id: string; +} + +interface IdlLoader { + load(path: string): Promise; + resolve(basePath: string, includePath: string): string | null; +} + +/** + * Loads IDL files from the local filesystem. + * Resolves relative include paths against the directory of the including file. + */ +class FsLoader implements IdlLoader { + async load(path: string): Promise { + const canonical = resolve(path); + const content = await readFile(canonical, 'utf-8'); + return { content, id: canonical }; + } + + resolve(basePath: string, includePath: string): string | null { + if (includePath.startsWith('git://')) return null; + const baseDir = dirname(resolve(basePath)); + return resolve(baseDir, includePath); + } +} + +/** + * Loads IDL files from git:// URLs via HTTPS. + * Format: git://github.com/user/repo/path/to/file.idl?branch + */ +class GitLoader implements IdlLoader { + async load(path: string): Promise { + const url = this.toRawUrl(path); + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`); + } + const content = await response.text(); + return { content, id: path }; + } + + resolve(basePath: string, includePath: string): string | null { + if (includePath.startsWith('git://')) return includePath; + if (!basePath.startsWith('git://')) return null; + + // Resolve relative paths within the same git repo + const baseUrl = new URL(basePath.replace('git://', 'https://')); + const baseParts = baseUrl.pathname.split('/'); + baseParts.pop(); // remove filename + baseParts.push(includePath); + baseUrl.pathname = baseParts.join('/'); + return 'git://' + baseUrl.hostname + baseUrl.pathname + baseUrl.search; + } + + private toRawUrl(gitUrl: string): string { + // git://github.com/user/repo/path/to/file.idl?branch + const url = new URL(gitUrl.replace('git://', 'https://')); + const parts = url.pathname.split('/').filter(Boolean); + if (parts.length < 3) { + throw new Error(`Invalid git URL: ${gitUrl}. Expected git://host/user/repo/path?branch`); + } + const [user, repo, ...pathParts] = parts; + const branch = (url.searchParams.get('branch') ?? url.search.slice(1)) || 'main'; + const host = url.hostname; + + if (host === 'github.com') { + return `https://raw.githubusercontent.com/${user}/${repo}/${branch}/${pathParts.join('/')}`; + } + // Fallback: assume GitLab-style raw URL + return `https://${host}/${user}/${repo}/-/raw/${branch}/${pathParts.join('/')}`; + } +} + +const fsLoader = new FsLoader(); +const gitLoader = new GitLoader(); +const defaultLoaders: IdlLoader[] = [fsLoader, gitLoader]; + +/** + * Preprocess an IDL file, resolving !@include directives recursively. + * Mirrors the logic in rs/idl-parser-v2/src/preprocess/mod.rs. + */ +export async function preprocessIdl( + path: string, + loaders: IdlLoader[] = defaultLoaders, +): Promise { + const visited = new Set(); + const result: string[] = []; + await preprocessRecursive(path, loaders, visited, result); + return result.join(''); +} + +async function preprocessRecursive( + path: string, + loaders: IdlLoader[], + visited: Set, + out: string[], +): Promise { + // Find a loader that can handle this path + const loader = loaders.find((l) => l.resolve(path, path) !== null); + if (!loader) { + throw new Error(`No loader can handle path: ${path}`); + } + + const source = await loader.load(path); + + // Deduplication + if (visited.has(source.id)) { + return; + } + visited.add(source.id); + + for (const line of source.content.split('\n')) { + const trimmed = line.trim(); + + if (trimmed.startsWith('!@include:')) { + const rest = trimmed.slice('!@include:'.length).trim(); + const includePath = rest.replace(/^["']|["']$/g, ''); + + if (!includePath) { + throw new Error('Invalid include directive'); + } + + // Find a loader that can resolve this include + let nextPath: string | null = null; + for (const l of loaders) { + nextPath = l.resolve(path, includePath); + if (nextPath !== null) break; + } + + if (nextPath === null) { + throw new Error(`No loader can resolve include '${includePath}' from: ${path}`); + } + + await preprocessRecursive(nextPath, loaders, visited, out); + + // Ensure newline after included content + if (out.length > 0 && !out[out.length - 1].endsWith('\n')) { + out.push('\n'); + } + } else { + out.push(line + '\n'); + } + } +} diff --git a/js/mcp-server/src/index.ts b/js/mcp-server/src/index.ts new file mode 100644 index 000000000..db5aa05e8 --- /dev/null +++ b/js/mcp-server/src/index.ts @@ -0,0 +1,43 @@ +#!/usr/bin/env bun +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; + +import { registerIdlTools, getParser } from './tools/idl-tools.js'; +import { registerSourceTools } from './tools/source-tools.js'; +import { registerCodecTools } from './tools/codec-tools.js'; +import { registerHeaderTools } from './tools/header-tools.js'; +import { registerTypeTools } from './tools/type-tools.js'; +import { registerUtilTools } from './tools/util-tools.js'; +import { registerResources } from './resources.js'; + +const server = new McpServer( + { + name: 'sails-mcp', + version: '0.5.1', + }, + { + instructions: + 'Sails IDL & Program development server. Start by parsing an IDL with sails_parse_idl ' + + 'or loading from file with sails_load_idl. Then use encoding/decoding tools to work with payloads. ' + + 'All encode/decode tools require a program to be registered first. ' + + 'Use sails_list_programs to see registered programs.', + }, +); + +// Register all tool categories +registerIdlTools(server); +registerSourceTools(server); +registerCodecTools(server); +registerHeaderTools(server); +registerTypeTools(server); +registerUtilTools(server); +registerResources(server); + +// Initialize the WASM parser eagerly so first tool call is fast +getParser().catch((err) => { + console.error('Warning: Failed to pre-initialize IDL parser:', err.message); +}); + +// Start the stdio transport +const transport = new StdioServerTransport(); +await server.connect(transport); diff --git a/js/mcp-server/src/registry.ts b/js/mcp-server/src/registry.ts new file mode 100644 index 000000000..1ced3c60c --- /dev/null +++ b/js/mcp-server/src/registry.ts @@ -0,0 +1,48 @@ +import { SailsProgram, SailsService } from 'sails-js'; +import type { IIdlDoc } from 'sails-js-types'; + +export interface RegisteredProgram { + name: string; + doc: IIdlDoc; + program: SailsProgram; +} + +/** + * Session-scoped registry of parsed Sails programs. + * Keyed by program name (from IDL or user-provided). + */ +class ProgramRegistry { + private programs = new Map(); + + register(name: string, doc: IIdlDoc): RegisteredProgram { + const program = new SailsProgram(doc); + const entry: RegisteredProgram = { name, doc, program }; + this.programs.set(name, entry); + return entry; + } + + get(name: string): RegisteredProgram | undefined { + return this.programs.get(name); + } + + getOrThrow(name: string): RegisteredProgram { + const entry = this.programs.get(name); + if (!entry) { + const available = this.list().map((p) => p.name); + throw new Error( + `Program "${name}" not found. Available: [${available.join(', ')}]. Use sails_parse_idl or sails_load_idl first.`, + ); + } + return entry; + } + + list(): RegisteredProgram[] { + return Array.from(this.programs.values()); + } + + has(name: string): boolean { + return this.programs.has(name); + } +} + +export const registry = new ProgramRegistry(); diff --git a/js/mcp-server/src/resources.ts b/js/mcp-server/src/resources.ts new file mode 100644 index 000000000..eb49a888f --- /dev/null +++ b/js/mcp-server/src/resources.ts @@ -0,0 +1,74 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Resolve paths relative to the repo root (js/mcp-server -> repo root) +function repoRoot(): string { + const thisDir = dirname(fileURLToPath(import.meta.url)); + return resolve(thisDir, '..', '..', '..'); +} + +async function readRepoFile(relativePath: string): Promise { + const fullPath = resolve(repoRoot(), relativePath); + return readFile(fullPath, 'utf-8'); +} + +export function registerResources(server: McpServer) { + server.registerResource( + 'sails://specs/header-v1', + 'sails://specs/header-v1', + { + description: 'Sails Message Header v1 specification — 16-byte binary header format for routing messages.', + mimeType: 'text/markdown', + }, + async () => { + const content = await readRepoFile('docs/sails-header-v1-spec.md'); + return { contents: [{ uri: 'sails://specs/header-v1', text: content, mimeType: 'text/markdown' }] }; + }, + ); + + server.registerResource( + 'sails://specs/idl-v2', + 'sails://specs/idl-v2', + { + description: 'Sails IDL v2 language specification — grammar, types, services, programs.', + mimeType: 'text/markdown', + }, + async () => { + const content = await readRepoFile('docs/idl-v2-spec.md'); + return { contents: [{ uri: 'sails://specs/idl-v2', text: content, mimeType: 'text/markdown' }] }; + }, + ); + + server.registerResource( + 'sails://specs/interface-id', + 'sails://specs/interface-id', + { + description: 'Interface ID specification — how structural BLAKE3 hashes identify services.', + mimeType: 'text/markdown', + }, + async () => { + const spec = await readRepoFile('docs/interface-id-spec.md'); + const hash = await readRepoFile('docs/reflect-hash-spec.md'); + return { + contents: [ + { uri: 'sails://specs/interface-id', text: `${spec}\n\n---\n\n${hash}`, mimeType: 'text/markdown' }, + ], + }; + }, + ); + + server.registerResource( + 'sails://examples/demo', + 'sails://examples/demo', + { + description: 'Complete demo IDL file showing services, events, types, constructors, and inheritance.', + mimeType: 'text/plain', + }, + async () => { + const content = await readRepoFile('examples/demo/client/demo_client.idl'); + return { contents: [{ uri: 'sails://examples/demo', text: content, mimeType: 'text/plain' }] }; + }, + ); +} diff --git a/js/mcp-server/src/summarize.ts b/js/mcp-server/src/summarize.ts new file mode 100644 index 000000000..b927f2cc8 --- /dev/null +++ b/js/mcp-server/src/summarize.ts @@ -0,0 +1,144 @@ +import type { RegisteredProgram } from './registry.js'; +import type { IServiceUnit, IServiceFunc, IFuncParam, IServiceEvent, TypeDecl } from 'sails-js-types'; + +function interfaceIdToString(id: any): string | null { + if (!id) return null; + if (typeof id === 'string') return id; + if (typeof id.toString === 'function') return id.toString(); + return null; +} + +function typeDeclToString(td: TypeDecl): string { + if (!td) return 'unknown'; + if (typeof td === 'string') return td; + if ('primitive' in td) return td.primitive; + if ('optional' in td) return `Option<${typeDeclToString(td.optional)}>`; + if ('vec' in td) return `Vec<${typeDeclToString(td.vec)}>`; + if ('result' in td) return `Result<${typeDeclToString(td.result.ok)}, ${typeDeclToString(td.result.err)}>`; + if ('map' in td) return `BTreeMap<${typeDeclToString(td.map.key)}, ${typeDeclToString(td.map.value)}>`; + if ('fixedArray' in td) return `[${typeDeclToString(td.fixedArray.type)}; ${td.fixedArray.len}]`; + if ('tuple' in td) return `(${td.tuple.map(typeDeclToString).join(', ')})`; + if ('userDefined' in td) { + const name = td.userDefined.name; + if (td.userDefined.params?.length) { + return `${name}<${td.userDefined.params.map(typeDeclToString).join(', ')}>`; + } + return name; + } + return JSON.stringify(td); +} + +function summarizeParams(params: IFuncParam[]) { + return params.map((p) => ({ + name: p.name, + type: typeDeclToString(p.type), + })); +} + +function summarizeFunc(func: IServiceFunc, idx: number) { + const entryIdAnn = func.annotations?.find(([k]) => k === 'entry-id'); + const entryId = entryIdAnn ? Number(entryIdAnn[1]) : idx; + return { + name: func.name, + kind: func.kind ?? 'command', + entry_id: entryId, + params: summarizeParams(func.params), + return_type: func.output ? typeDeclToString(func.output) : 'void', + throws: func.throws ? typeDeclToString(func.throws) : undefined, + docs: func.docs?.join('\n') || undefined, + }; +} + +function summarizeEvent(event: IServiceEvent, idx: number) { + const entryIdAnn = event.annotations?.find(([k]) => k === 'entry-id'); + const entryId = entryIdAnn ? Number(entryIdAnn[1]) : idx; + return { + name: event.name, + entry_id: entryId, + fields: event.fields?.map((f) => ({ + name: f.name, + type: typeDeclToString(f.type), + })) ?? [], + docs: event.docs?.join('\n') || undefined, + }; +} + +function findServiceUnit(entry: RegisteredProgram, serviceName: string): IServiceUnit { + const unit = entry.doc.services?.find((s) => s.name === serviceName); + if (!unit) { + const available = entry.doc.services?.map((s) => s.name) ?? []; + throw new Error( + `Service "${serviceName}" not found in program "${entry.name}". Available: [${available.join(', ')}]`, + ); + } + return unit; +} + +export function summarizeProgram(entry: RegisteredProgram) { + const doc = entry.doc; + return { + program: entry.name, + constructors: doc.program?.ctors?.map((c, idx) => ({ + name: c.name, + params: summarizeParams(c.params), + throws: c.throws ? typeDeclToString(c.throws) : undefined, + docs: c.docs?.join('\n') || undefined, + })) ?? [], + services: doc.program?.services?.map((expo) => { + const unit = doc.services?.find((s) => s.name === expo.name); + return { + name: expo.name, + interface_id: interfaceIdToString(unit?.interface_id ?? expo.interface_id), + route_idx: expo.route_idx ?? 0, + function_count: unit?.funcs?.length ?? 0, + event_count: unit?.events?.length ?? 0, + extends: unit?.extends?.map((e) => e.name) ?? [], + }; + }) ?? [], + type_count: doc.services?.reduce((sum, s) => sum + (s.types?.length ?? 0), 0) ?? 0, + }; +} + +export function summarizeService(entry: RegisteredProgram, serviceName: string) { + const unit = findServiceUnit(entry, serviceName); + return { + name: unit.name, + interface_id: interfaceIdToString(unit.interface_id), + functions: unit.funcs?.map(summarizeFunc) ?? [], + events: unit.events?.map(summarizeEvent) ?? [], + types: unit.types?.map((t) => ({ + name: t.name, + def: t.def, + })) ?? [], + extends: unit.extends?.map((e) => ({ + name: e.name, + interface_id: interfaceIdToString(e.interface_id), + })) ?? [], + annotations: unit.annotations ?? [], + }; +} + +export function summarizeFunction( + entry: RegisteredProgram, + serviceName: string, + funcName: string, +) { + const unit = findServiceUnit(entry, serviceName); + const allFuncs = unit.funcs ?? []; + const idx = allFuncs.findIndex((f) => f.name === funcName); + if (idx === -1) { + const available = allFuncs.map((f) => f.name); + throw new Error( + `Function "${funcName}" not found in service "${serviceName}". Available: [${available.join(', ')}]`, + ); + } + const func = allFuncs[idx]; + const detail = summarizeFunc(func, idx); + + // Also include the service context + return { + ...detail, + service: serviceName, + interface_id: interfaceIdToString(unit.interface_id), + }; +} diff --git a/js/mcp-server/src/tools/codec-tools.ts b/js/mcp-server/src/tools/codec-tools.ts new file mode 100644 index 000000000..d933da9b1 --- /dev/null +++ b/js/mcp-server/src/tools/codec-tools.ts @@ -0,0 +1,263 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { z } from 'zod'; +import { registry } from '../registry.js'; + +function getServiceFuncs(programName: string, serviceName: string) { + const entry = registry.getOrThrow(programName); + const services = entry.program.services; + const service = services[serviceName]; + if (!service) { + const available = Object.keys(services); + throw new Error( + `Service "${serviceName}" not found in program "${programName}". Available: [${available.join(', ')}]`, + ); + } + return service; +} + +function getFunction(programName: string, serviceName: string, funcName: string) { + const service = getServiceFuncs(programName, serviceName); + // Search in both functions and queries + const func = service.functions[funcName] ?? service.queries[funcName]; + if (!func) { + const available = [...Object.keys(service.functions), ...Object.keys(service.queries)]; + throw new Error( + `Function "${funcName}" not found in service "${serviceName}". Available: [${available.join(', ')}]`, + ); + } + return func; +} + +export function registerCodecTools(server: McpServer) { + server.registerTool( + 'sails_encode_payload', + { + description: + 'Encode a Sails function call to a hex string. Constructs the full message: 16-byte Sails Header v1 + SCALE-encoded arguments. ' + + 'The program must be parsed first via sails_parse_idl or sails_load_idl. ' + + 'Pass args as a JSON array matching the function parameter order. ' + + 'Type coercion: ActorId as "0x..." hex string, Option as null or value, enums as {"VariantName": value} or "UnitVariant".', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name (e.g. "Counter")'), + function: z.string().describe('Function name (e.g. "Add")'), + args: z + .array(z.any()) + .default([]) + .describe('Function arguments as JSON array, in parameter order'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, function: funcName, args }) => { + try { + const func = getFunction(programName, serviceName, funcName); + const hex = func.encodePayload(...args); + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + hex, + args_used: func.args.map((a, i) => ({ + name: a.name, + type: a.type, + value: args[i] ?? null, + })), + }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Encode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_decode_payload', + { + description: + 'Decode a hex payload back to structured arguments for a known function call. ' + + 'Parses the 16-byte Sails header and SCALE-decodes the remaining bytes. ' + + 'You must specify which program/service/function the payload belongs to.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + function: z.string().describe('Function name'), + hex: z.string().describe('Hex-encoded payload (with or without 0x prefix)'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, function: funcName, hex }) => { + try { + const func = getFunction(programName, serviceName, funcName); + const decoded = func.decodePayload(hex as `0x${string}`); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ service: serviceName, function: funcName, args: decoded }, null, 2), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Decode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_decode_result', + { + description: + 'Decode a function reply/result from hex. Strips the 16-byte Sails header and SCALE-decodes ' + + 'the return value according to the function return type from the IDL.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + function: z.string().describe('Function name'), + hex: z.string().describe('Hex-encoded result payload'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, function: funcName, hex }) => { + try { + const func = getFunction(programName, serviceName, funcName); + const result = func.decodeResult(hex as `0x${string}`); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ service: serviceName, function: funcName, result }, null, 2), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Decode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_encode_constructor', + { + description: + 'Encode a program constructor call to hex. Used for program initialization (upload_program / create_program).', + inputSchema: { + program: z.string().describe('Registered program name'), + constructor: z.string().describe('Constructor name (e.g. "New", "Default")'), + args: z.array(z.any()).default([]).describe('Constructor arguments as JSON array'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, constructor: ctorName, args }) => { + try { + const entry = registry.getOrThrow(programName); + const ctors = entry.program.ctors; + if (!ctors) { + throw new Error(`Program "${programName}" has no constructors`); + } + const ctor = ctors[ctorName]; + if (!ctor) { + const available = Object.keys(ctors); + throw new Error( + `Constructor "${ctorName}" not found. Available: [${available.join(', ')}]`, + ); + } + const hex = ctor.encodePayload(...args); + return { + content: [{ type: 'text', text: JSON.stringify({ hex }, null, 2) }], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Encode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_decode_event', + { + description: + 'Decode an event payload from hex. If event name is omitted, auto-detects by matching ' + + "the header's interface_id + entry_id against all events in the service. " + + 'Returns the event name and decoded field values.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + hex: z.string().describe('Hex-encoded event payload'), + event: z + .string() + .optional() + .describe('Event name. If omitted, auto-detects from header entry_id.'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, hex, event: eventName }) => { + try { + const service = getServiceFuncs(programName, serviceName); + const events = service.events; + + if (eventName) { + const ev = events[eventName]; + if (!ev) { + const available = Object.keys(events); + throw new Error( + `Event "${eventName}" not found in service "${serviceName}". Available: [${available.join(', ')}]`, + ); + } + const data = ev.decode(hex as `0x${string}`); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ event: eventName, data }, null, 2), + }, + ], + }; + } + + // Auto-detect: try each event's decode + for (const [name, ev] of Object.entries(events)) { + try { + const data = ev.decode(hex as `0x${string}`); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ event: name, data, auto_detected: true }, null, 2), + }, + ], + }; + } catch { + continue; + } + } + + throw new Error( + `Could not match event in service "${serviceName}". No event entry_id matched the payload header.`, + ); + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Event decode error: ${err.message}` }], + }; + } + }, + ); +} diff --git a/js/mcp-server/src/tools/header-tools.ts b/js/mcp-server/src/tools/header-tools.ts new file mode 100644 index 000000000..a85437b5a --- /dev/null +++ b/js/mcp-server/src/tools/header-tools.ts @@ -0,0 +1,215 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { z } from 'zod'; +import { SailsMessageHeader, InterfaceId } from 'sails-js-parser-idl-v2'; +import { registry } from '../registry.js'; + +function hexToBytes(hex: string): Uint8Array { + let h = hex.startsWith('0x') ? hex.slice(2) : hex; + if (h.length % 2 !== 0) h = '0' + h; + const bytes = new Uint8Array(h.length / 2); + for (let i = 0; i < bytes.length; i++) { + bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16); + } + return bytes; +} + +function bytesToHex(bytes: Uint8Array): string { + return '0x' + Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join(''); +} + +export function registerHeaderTools(server: McpServer) { + server.registerTool( + 'sails_parse_header', + { + description: + 'Parse a raw Sails Message Header from hex. No IDL or program registration needed. ' + + 'Extracts: magic bytes ("GM"), version, header length, interface ID, entry ID, route index. ' + + 'Also returns the remaining payload after the header.', + inputSchema: { + hex: z.string().describe('Hex-encoded payload containing at least 16 bytes for the header'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ hex }) => { + try { + const bytes = hexToBytes(hex); + const { header, offset } = SailsMessageHeader.tryReadBytes(bytes, 0); + const payloadAfterHeader = bytes.slice(offset); + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + valid: true, + magic: 'GM', + version: header.version, + header_length: header.hlen, + interface_id: header.interfaceId.toString(), + interface_id_u64: header.interfaceId.asU64().toString(), + entry_id: header.entryId, + route_idx: header.routeIdx, + payload_after_header: bytesToHex(payloadAfterHeader), + payload_length: payloadAfterHeader.length, + }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Header parse error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_build_header', + { + description: + 'Build a 16-byte Sails Message Header v1 from explicit components. ' + + 'Useful for manual message construction or testing.', + inputSchema: { + interface_id: z + .string() + .describe('Interface ID as hex string (e.g. "0x579d6daba41b7d82")'), + entry_id: z.number().int().min(0).max(65535).describe('Entry ID (u16, 0-65535)'), + route_idx: z.number().int().min(0).max(255).default(0).describe('Route index (u8, 0-255)'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ interface_id, entry_id, route_idx }) => { + try { + const iid = InterfaceId.fromString(interface_id); + const header = SailsMessageHeader.v1(iid, entry_id, route_idx); + const bytes = header.toBytes(); + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + hex: bytesToHex(bytes), + bytes: Array.from(bytes), + }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Header build error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_verify_interface_id', + { + description: + 'Show the computed and declared interface IDs for a service. ' + + 'The IDL parser computes interface IDs structurally (BLAKE3 hash of the service shape). ' + + 'If the service has an explicit @0x... annotation, this tool compares computed vs declared. ' + + 'Essential for @partial service compatibility checks.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName }) => { + try { + const entry = registry.getOrThrow(programName); + const unit = entry.doc.services?.find((s) => s.name === serviceName); + if (!unit) { + const available = entry.doc.services?.map((s) => s.name) ?? []; + throw new Error( + `Service "${serviceName}" not found. Available: [${available.join(', ')}]`, + ); + } + + const isPartial = unit.annotations?.some(([k]) => k === 'partial') ?? false; + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + service: serviceName, + interface_id: unit.interface_id ?? null, + is_partial: isPartial, + note: isPartial + ? '@partial services require an explicit interface_id in the IDL.' + : 'Interface ID is computed structurally from the service definition.', + }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: err.message }], + }; + } + }, + ); + + server.registerTool( + 'sails_list_interface_ids', + { + description: + 'List all services in a parsed program with their interface IDs and entry ID maps for functions and events.', + inputSchema: { + program: z.string().describe('Registered program name'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName }) => { + try { + const entry = registry.getOrThrow(programName); + const result = (entry.doc.services ?? []).map((unit) => ({ + service: unit.name, + interface_id: unit.interface_id ?? null, + functions: (unit.funcs ?? []).map((f, idx) => { + const ann = f.annotations?.find(([k]) => k === 'entry-id'); + return { + name: f.name, + entry_id: ann ? Number(ann[1]) : idx, + kind: f.kind ?? 'command', + }; + }), + events: (unit.events ?? []).map((e, idx) => { + const ann = e.annotations?.find(([k]) => k === 'entry-id'); + return { + name: e.name, + entry_id: ann ? Number(ann[1]) : idx, + }; + }), + })); + + return { + content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: err.message }], + }; + } + }, + ); +} diff --git a/js/mcp-server/src/tools/idl-tools.ts b/js/mcp-server/src/tools/idl-tools.ts new file mode 100644 index 000000000..a1dfe9a3b --- /dev/null +++ b/js/mcp-server/src/tools/idl-tools.ts @@ -0,0 +1,147 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { z } from 'zod'; +import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { registry } from '../registry.js'; +import { summarizeProgram, summarizeService, summarizeFunction } from '../summarize.js'; + +let parser: SailsIdlParser | null = null; + +export async function getParser(): Promise { + if (!parser) { + parser = new SailsIdlParser(); + await parser.init(); + } + return parser; +} + +export function registerIdlTools(server: McpServer) { + server.registerTool( + 'sails_parse_idl', + { + description: + 'Parse Sails IDL v2 text and register the program for subsequent encoding/decoding operations. ' + + 'Returns a structured summary of services, constructors, types, events, and interface IDs. ' + + 'Does NOT resolve !@include directives — use sails_load_idl for IDL files with includes.', + inputSchema: { + idl: z.string().describe('Raw IDL v2 text'), + program: z + .string() + .optional() + .describe('Name to register the program under. Defaults to the program name from IDL.'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ idl, program }) => { + try { + const p = await getParser(); + const doc = p.parse(idl); + + const name = program ?? doc.program?.name ?? 'unnamed'; + const entry = registry.register(name, doc); + const summary = summarizeProgram(entry); + + return { + content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `IDL parse error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_validate_idl', + { + description: + 'Validate Sails IDL v2 text without registering it. Returns parse errors and warnings. ' + + 'Use this to check IDL syntax before committing or deploying.', + inputSchema: { + idl: z.string().describe('Raw IDL v2 text to validate'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ idl }) => { + try { + const p = await getParser(); + p.parse(idl); + return { + content: [{ type: 'text', text: JSON.stringify({ valid: true, errors: null }, null, 2) }], + }; + } catch (err: any) { + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { valid: false, errors: [err.message] }, + null, + 2, + ), + }, + ], + }; + } + }, + ); + + server.registerTool( + 'sails_inspect_service', + { + description: + 'Get detailed information about a specific service including all functions, queries, events, types, ' + + 'extended services, and its interface ID. Requires the program to be parsed first via sails_parse_idl.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name (e.g. "Counter")'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName }) => { + try { + const entry = registry.getOrThrow(programName); + const detail = summarizeService(entry, serviceName); + return { + content: [{ type: 'text', text: JSON.stringify(detail, null, 2) }], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: err.message }], + }; + } + }, + ); + + server.registerTool( + 'sails_inspect_function', + { + description: + 'Get detailed information about a specific function or query, including parameter types, ' + + 'return type, SCALE codec type strings, entry ID, and documentation. ' + + 'Requires the program to be parsed first via sails_parse_idl.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + function: z.string().describe('Function or query name'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, function: funcName }) => { + try { + const entry = registry.getOrThrow(programName); + const detail = summarizeFunction(entry, serviceName, funcName); + return { + content: [{ type: 'text', text: JSON.stringify(detail, null, 2) }], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: err.message }], + }; + } + }, + ); +} diff --git a/js/mcp-server/src/tools/source-tools.ts b/js/mcp-server/src/tools/source-tools.ts new file mode 100644 index 000000000..6f5813b24 --- /dev/null +++ b/js/mcp-server/src/tools/source-tools.ts @@ -0,0 +1,93 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { z } from 'zod'; +import { registry } from '../registry.js'; +import { preprocessIdl } from '../idl-loader.js'; +import { extractIdlFromWasm } from '../wasm-extractor.js'; +import { getParser } from './idl-tools.js'; +import { summarizeProgram } from '../summarize.js'; + +export function registerSourceTools(server: McpServer) { + server.registerTool( + 'sails_load_idl', + { + description: + 'Load an IDL file from a file path, resolving !@include directives recursively ' + + '(supports local files and git:// URLs). Preprocesses into a single IDL text, ' + + 'then parses and registers the program for subsequent operations. ' + + 'Use this instead of sails_parse_idl when your IDL has !@include statements.', + inputSchema: { + path: z.string().describe('Path to the .idl file (absolute or relative)'), + program: z + .string() + .optional() + .describe('Name to register the program under. Defaults to the program name from IDL.'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ path, program }) => { + try { + const preprocessed = await preprocessIdl(path); + const p = await getParser(); + const doc = p.parse(preprocessed); + + const name = program ?? doc.program?.name ?? 'unnamed'; + const entry = registry.register(name, doc); + const summary = summarizeProgram(entry); + + return { + content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Load IDL error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_extract_idl_from_wasm', + { + description: + 'Extract embedded IDL from a .wasm binary\'s "sails:idl" custom section. ' + + 'Returns the raw IDL text which can then be passed to sails_parse_idl. ' + + 'The IDL may be deflate-compressed inside the WASM. ' + + 'Useful for debugging deployed programs when you have the .wasm but not the .idl file.', + inputSchema: { + wasm_path: z.string().describe('Path to the .wasm binary file'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ wasm_path }) => { + try { + const idl = await extractIdlFromWasm(wasm_path); + if (idl === null) { + return { + isError: true, + content: [ + { + type: 'text', + text: 'No "sails:idl" custom section found in the WASM binary. ' + + 'The program may not have been built with IDL embedding (cargo sails idl-embed).', + }, + ], + }; + } + return { + content: [ + { + type: 'text', + text: JSON.stringify({ idl, length: idl.length }, null, 2), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `WASM extract error: ${err.message}` }], + }; + } + }, + ); +} diff --git a/js/mcp-server/src/tools/type-tools.ts b/js/mcp-server/src/tools/type-tools.ts new file mode 100644 index 000000000..2a995d859 --- /dev/null +++ b/js/mcp-server/src/tools/type-tools.ts @@ -0,0 +1,171 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { z } from 'zod'; +import { registry } from '../registry.js'; + +export function registerTypeTools(server: McpServer) { + server.registerTool( + 'sails_resolve_type', + { + description: + 'Resolve a user-defined type from the IDL into its full definition. ' + + 'Shows struct fields, enum variants, and how the type maps to SCALE codec. ' + + 'If the type is service-scoped, specify the service name.', + inputSchema: { + program: z.string().describe('Registered program name'), + type_name: z.string().describe('Type name (e.g. "DoThatParam", "ManyVariants")'), + service: z.string().optional().describe('Service name (for service-scoped types)'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, type_name, service: serviceName }) => { + try { + const entry = registry.getOrThrow(programName); + const doc = entry.doc; + + // Search in service-scoped types first, then program-level types + const searchScopes: Array<{ scope: string; types: any[] }> = []; + + if (serviceName) { + const unit = doc.services?.find((s) => s.name === serviceName); + if (unit?.types) { + searchScopes.push({ scope: serviceName, types: unit.types }); + } + } else { + // Search all scopes + if (doc.program?.types) { + searchScopes.push({ scope: 'program', types: doc.program.types }); + } + for (const svc of doc.services ?? []) { + if (svc.types) { + searchScopes.push({ scope: svc.name, types: svc.types }); + } + } + } + + for (const { scope, types } of searchScopes) { + const found = types.find((t: any) => t.name === type_name); + if (found) { + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + name: found.name, + scope, + definition: found.def, + }, + null, + 2, + ), + }, + ], + }; + } + } + + // Collect all available type names for the error message + const allTypes: string[] = []; + for (const { types } of searchScopes) { + for (const t of types) { + allTypes.push(t.name); + } + } + + throw new Error( + `Type "${type_name}" not found. Available types: [${allTypes.join(', ')}]`, + ); + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: err.message }], + }; + } + }, + ); + + server.registerTool( + 'sails_encode_type', + { + description: + 'SCALE-encode a JSON value for a specific IDL type. Useful for constructing payload fragments ' + + 'or testing type encoding independently. Requires specifying the service context for type resolution.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name (for type resolution context)'), + type_name: z.string().describe('Type name or SCALE type expression (e.g. "u32", "DoThatParam")'), + value: z.any().describe('JSON value to encode'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, type_name, value }) => { + try { + const entry = registry.getOrThrow(programName); + const services = entry.program.services; + const service = services[serviceName]; + if (!service) { + throw new Error(`Service "${serviceName}" not found`); + } + + const encoded = service.registry.createType(type_name, value); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ hex: encoded.toHex(), type: type_name }, null, 2), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Encode type error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_decode_type', + { + description: + 'SCALE-decode a hex value for a specific IDL type. Returns the decoded JSON value.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name (for type resolution context)'), + type_name: z.string().describe('Type name or SCALE type expression'), + hex: z.string().describe('Hex-encoded value'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, type_name, hex }) => { + try { + const entry = registry.getOrThrow(programName); + const services = entry.program.services; + const service = services[serviceName]; + if (!service) { + throw new Error(`Service "${serviceName}" not found`); + } + + const decoded = service.registry.createType(type_name, hex as `0x${string}`); + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { value: decoded.toJSON(), type: type_name }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Decode type error: ${err.message}` }], + }; + } + }, + ); +} diff --git a/js/mcp-server/src/tools/util-tools.ts b/js/mcp-server/src/tools/util-tools.ts new file mode 100644 index 000000000..f5b0730dd --- /dev/null +++ b/js/mcp-server/src/tools/util-tools.ts @@ -0,0 +1,264 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { z } from 'zod'; +import { SailsMessageHeader } from 'sails-js-parser-idl-v2'; +import { registry } from '../registry.js'; + +const SAILS_MAGIC = new Uint8Array([0x47, 0x4d]); // "GM" + +function hexToBytes(hex: string): Uint8Array { + let h = hex.startsWith('0x') ? hex.slice(2) : hex; + if (h.length % 2 !== 0) h = '0' + h; + const bytes = new Uint8Array(h.length / 2); + for (let i = 0; i < bytes.length; i++) { + bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16); + } + return bytes; +} + +export function registerUtilTools(server: McpServer) { + server.registerTool( + 'sails_list_programs', + { + description: + 'List all programs currently registered in the MCP session. ' + + 'Shows program names, service counts, and constructor counts.', + inputSchema: {}, + annotations: { readOnlyHint: true }, + }, + async () => { + const programs = registry.list().map((entry) => ({ + program: entry.name, + services: Object.keys(entry.program.services), + constructors: entry.program.ctors ? Object.keys(entry.program.ctors) : [], + })); + + if (programs.length === 0) { + return { + content: [ + { + type: 'text', + text: 'No programs registered. Use sails_parse_idl or sails_load_idl to register a program first.', + }, + ], + }; + } + + return { + content: [{ type: 'text', text: JSON.stringify(programs, null, 2) }], + }; + }, + ); + + server.registerTool( + 'sails_detect_encoding', + { + description: + 'Detect whether a hex payload uses Sails Message Header (SCALE encoding) or ' + + 'ABI encoding (4-byte selector). Checks for the "GM" (0x474D) magic bytes. ' + + 'No program registration required.', + inputSchema: { + hex: z.string().describe('Hex-encoded payload to analyze'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ hex }) => { + try { + const bytes = hexToBytes(hex); + + if (bytes.length < 4) { + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + encoding: 'unknown', + reason: 'Payload too short (< 4 bytes)', + }, + null, + 2, + ), + }, + ], + }; + } + + // Check for Sails magic bytes "GM" (0x47 0x4D) + if (bytes[0] === SAILS_MAGIC[0] && bytes[1] === SAILS_MAGIC[1]) { + const details: any = { encoding: 'scale', magic: 'GM (0x474D)' }; + + if (bytes.length >= 16) { + try { + const { header } = SailsMessageHeader.tryReadBytes(bytes, 0); + details.version = header.version; + details.interface_id = header.interfaceId.toString(); + details.entry_id = header.entryId; + details.route_idx = header.routeIdx; + } catch { + details.note = 'Magic bytes present but header parse failed'; + } + } + + return { + content: [{ type: 'text', text: JSON.stringify(details, null, 2) }], + }; + } + + // No Sails magic - likely ABI encoding (4-byte selector) + const selector = '0x' + Array.from(bytes.slice(0, 4)).map((b) => b.toString(16).padStart(2, '0')).join(''); + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + encoding: 'abi', + selector, + note: 'No Sails "GM" magic bytes. Likely ABI-encoded (ethexe) with 4-byte function selector.', + payload_length: bytes.length, + }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Detection error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_explain_payload', + { + description: + 'Given a hex payload and a registered program, try to identify which service and function ' + + "it targets by matching the header's interface_id and entry_id. " + + 'Decodes the arguments if a match is found. Works for SCALE-encoded payloads with Sails headers.', + inputSchema: { + program: z.string().describe('Registered program name'), + hex: z.string().describe('Hex-encoded payload to identify'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, hex }) => { + try { + const bytes = hexToBytes(hex); + const entry = registry.getOrThrow(programName); + + // Try to parse the Sails header + const { ok, header } = SailsMessageHeader.tryFromBytes(bytes); + if (!ok || !header) { + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + identified: false, + reason: 'Not a valid Sails message (no "GM" magic bytes or invalid header)', + }, + null, + 2, + ), + }, + ], + }; + } + + const targetIidU64 = header.interfaceId.asU64(); + const targetEntryId = header.entryId; + + // Search all services for a match + for (const [serviceName, service] of Object.entries(entry.program.services)) { + // Check functions + for (const [funcName, func] of Object.entries(service.functions)) { + try { + const decoded = func.decodePayload(hex as `0x${string}`); + // If decodePayload succeeds without error, it's a match + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + identified: true, + service: serviceName, + function: funcName, + kind: 'command', + interface_id: header.interfaceId.toString(), + entry_id: targetEntryId, + args: decoded, + }, + null, + 2, + ), + }, + ], + }; + } catch { + continue; + } + } + + // Check queries + for (const [queryName, query] of Object.entries(service.queries)) { + try { + const decoded = query.decodePayload(hex as `0x${string}`); + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + identified: true, + service: serviceName, + function: queryName, + kind: 'query', + interface_id: header.interfaceId.toString(), + entry_id: targetEntryId, + args: decoded, + }, + null, + 2, + ), + }, + ], + }; + } catch { + continue; + } + } + } + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + identified: false, + interface_id: header.interfaceId.toString(), + entry_id: targetEntryId, + route_idx: header.routeIdx, + reason: `No matching service/function found for interface_id=${header.interfaceId.toString()} entry_id=${targetEntryId}`, + }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Explain error: ${err.message}` }], + }; + } + }, + ); +} diff --git a/js/mcp-server/src/wasm-extractor.ts b/js/mcp-server/src/wasm-extractor.ts new file mode 100644 index 000000000..fb754ae51 --- /dev/null +++ b/js/mcp-server/src/wasm-extractor.ts @@ -0,0 +1,125 @@ +import { readFile } from 'node:fs/promises'; +import { inflate } from 'node:zlib'; +import { promisify } from 'node:util'; + +const inflateAsync = promisify(inflate); + +const SECTION_NAME = 'sails:idl'; +const ENVELOPE_VERSION = 0x01; +const FLAG_COMPRESSED = 0x01; +const MAX_DECOMPRESSED_SIZE = 1024 * 1024; // 1 MB + +/** + * Extract IDL text from a WASM binary's "sails:idl" custom section. + * + * Mirrors the logic in rs/idl-embed/src/lib.rs. + * + * WASM custom sections have: + * - section id = 0 + * - name string (LEB128 length + UTF-8 name) + * - raw bytes (the payload) + * + * The envelope format is: + * - byte 0: version (must be 0x01) + * - byte 1: flags (0x01 = deflate compressed) + * - bytes 2+: content (raw or deflated IDL text) + */ +export async function extractIdlFromWasm(wasmPath: string): Promise { + const wasmBytes = await readFile(wasmPath); + return extractIdlFromBytes(wasmBytes); +} + +export function extractIdlFromBytes(wasmBytes: Buffer | Uint8Array): Promise { + return parseWasmCustomSection(wasmBytes, SECTION_NAME); +} + +async function parseWasmCustomSection( + wasm: Buffer | Uint8Array, + sectionName: string, +): Promise { + const view = new DataView(wasm.buffer, wasm.byteOffset, wasm.byteLength); + let offset = 0; + + // WASM magic: \0asm + if (wasm.length < 8) return null; + if (view.getUint32(0, true) !== 0x6d736100) return null; // \0asm in LE + offset = 4; + + // WASM version + const version = view.getUint32(offset, true); + if (version !== 1) return null; + offset += 4; + + // Iterate sections + while (offset < wasm.length) { + const sectionId = wasm[offset]; + offset += 1; + + // Read section size (LEB128) + const { value: sectionSize, bytesRead: sizeBytes } = readLeb128(wasm, offset); + offset += sizeBytes; + + const sectionEnd = offset + sectionSize; + + if (sectionId === 0) { + // Custom section - read name + const { value: nameLen, bytesRead: nameLenBytes } = readLeb128(wasm, offset); + const nameStart = offset + nameLenBytes; + const nameBytes = wasm.slice(nameStart, nameStart + nameLen); + const name = new TextDecoder().decode(nameBytes); + + if (name === sectionName) { + const dataStart = nameStart + nameLen; + const data = wasm.slice(dataStart, sectionEnd); + return decodeEnvelope(data); + } + } + + offset = sectionEnd; + } + + return null; +} + +async function decodeEnvelope(data: Uint8Array): Promise { + if (data.length < 2) return null; + + const version = data[0]; + if (version !== ENVELOPE_VERSION) return null; + + const flags = data[1]; + // Unknown flags - skip gracefully + if ((flags & ~FLAG_COMPRESSED) !== 0) return null; + + const content = data.slice(2); + + if (flags & FLAG_COMPRESSED) { + try { + const decompressed = await inflateAsync(content, { maxOutputLength: MAX_DECOMPRESSED_SIZE }); + return new TextDecoder().decode(decompressed); + } catch { + throw new Error('Failed to decompress IDL from WASM section'); + } + } else { + if (content.length > MAX_DECOMPRESSED_SIZE) { + throw new Error('IDL content exceeds maximum size (1MB)'); + } + return new TextDecoder().decode(content); + } +} + +function readLeb128(bytes: Uint8Array, offset: number): { value: number; bytesRead: number } { + let result = 0; + let shift = 0; + let bytesRead = 0; + + while (offset + bytesRead < bytes.length) { + const byte = bytes[offset + bytesRead]; + result |= (byte & 0x7f) << shift; + bytesRead++; + if ((byte & 0x80) === 0) break; + shift += 7; + } + + return { value: result, bytesRead }; +} diff --git a/js/mcp-server/tests/codec-tools.test.ts b/js/mcp-server/tests/codec-tools.test.ts new file mode 100644 index 000000000..2e0a641a6 --- /dev/null +++ b/js/mcp-server/tests/codec-tools.test.ts @@ -0,0 +1,112 @@ +import { describe, test, expect, beforeAll } from 'bun:test'; +import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { registry } from '../src/registry'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const thisDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(thisDir, '..', '..', '..'); +const demoIdlPath = resolve(repoRoot, 'js/test/demo-v2/demo.idl'); + +beforeAll(async () => { + const parser = new SailsIdlParser(); + await parser.init(); + const idl = await readFile(demoIdlPath, 'utf-8'); + const doc = parser.parse(idl); + registry.register('DemoClient', doc); +}); + +describe('SCALE codec encoding/decoding', () => { + test('encode Counter.Add(42)', () => { + const entry = registry.getOrThrow('DemoClient'); + const counter = entry.program.services['Counter']; + expect(counter).toBeDefined(); + + const addFn = counter.functions['Add']; + expect(addFn).toBeDefined(); + + const hex = addFn.encodePayload(42); + expect(hex).toBeDefined(); + expect(hex.startsWith('0x')).toBe(true); + + // Header is 16 bytes = 32 hex chars + "0x" prefix + // u32 is 4 bytes = 8 hex chars + // Total: 2 + 32 + 8 = 42 chars + expect(hex.length).toBe(42); + + // First two bytes should be "GM" magic (0x474d) + expect(hex.slice(2, 6)).toBe('474d'); + }); + + test('encode then decode Counter.Add round-trip', () => { + const entry = registry.getOrThrow('DemoClient'); + const addFn = entry.program.services['Counter'].functions['Add']; + + const hex = addFn.encodePayload(42); + const decoded = addFn.decodePayload(hex); + + expect(decoded).toEqual({ value: 42 }); + }); + + test('encode then decode result round-trip', () => { + const entry = registry.getOrThrow('DemoClient'); + const addFn = entry.program.services['Counter'].functions['Add']; + + // Encode a payload, then decode it as a result + // The result format is the same: [u8;16] header + return_type + const hex = addFn.encodePayload(99); + const result = addFn.decodeResult(hex); + + // The result is decoded as u32, should be 99 + expect(result).toBe(99); + }); + + test('encode PingPong.Ping with string arg', () => { + const entry = registry.getOrThrow('DemoClient'); + const pingFn = entry.program.services['PingPong'].functions['Ping']; + expect(pingFn).toBeDefined(); + + const hex = pingFn.encodePayload('hello'); + expect(hex.startsWith('0x474d')).toBe(true); + + const decoded = pingFn.decodePayload(hex); + expect(decoded).toEqual({ input: 'hello' }); + }); + + test('encode constructor Default()', () => { + const entry = registry.getOrThrow('DemoClient'); + const ctors = entry.program.ctors; + expect(ctors).toBeDefined(); + expect(ctors!['Default']).toBeDefined(); + + const hex = ctors!['Default'].encodePayload(); + expect(hex.startsWith('0x')).toBe(true); + // Default() takes no args, should be just the 16-byte header + expect(hex.length).toBe(34); // 0x + 32 hex chars + }); + + test('encode constructor New with args', () => { + const entry = registry.getOrThrow('DemoClient'); + const ctor = entry.program.ctors!['New']; + expect(ctor).toBeDefined(); + + const hex = ctor.encodePayload(42, [10, 20]); + expect(hex.startsWith('0x')).toBe(true); + + const decoded = ctor.decodePayload(hex); + expect(decoded.counter).toBe(42); + expect(decoded.dog_position).toEqual([10, 20]); + }); + + test('function with no args (Counter.Value query)', () => { + const entry = registry.getOrThrow('DemoClient'); + const valueFn = entry.program.services['Counter'].queries['Value']; + expect(valueFn).toBeDefined(); + + const hex = valueFn.encodePayload(); + expect(hex.startsWith('0x474d')).toBe(true); + // No args = just 16-byte header + expect(hex.length).toBe(34); + }); +}); diff --git a/js/mcp-server/tests/header-tools.test.ts b/js/mcp-server/tests/header-tools.test.ts new file mode 100644 index 000000000..c65ff6fa2 --- /dev/null +++ b/js/mcp-server/tests/header-tools.test.ts @@ -0,0 +1,54 @@ +import { describe, test, expect } from 'bun:test'; +import { SailsMessageHeader, InterfaceId } from 'sails-js-parser-idl-v2'; + +describe('Header operations', () => { + test('build and parse header round-trip', () => { + const iid = InterfaceId.fromString('0x579d6daba41b7d82'); + const header = SailsMessageHeader.v1(iid, 0, 1); + const bytes = header.toBytes(); + + expect(bytes.length).toBe(16); + // Magic: GM + expect(bytes[0]).toBe(0x47); + expect(bytes[1]).toBe(0x4d); + // Version: 1 + expect(bytes[2]).toBe(1); + // Header length: 16 + expect(bytes[3]).toBe(16); + + // Parse it back + const { header: parsed, offset } = SailsMessageHeader.tryReadBytes(bytes, 0); + expect(offset).toBe(16); + expect(parsed.version).toBe(1); + expect(parsed.hlen).toBe(16); + expect(parsed.interfaceId.toString()).toBe('0x579d6daba41b7d82'); + expect(parsed.entryId).toBe(0); + expect(parsed.routeIdx).toBe(1); + }); + + test('InterfaceId conversions', () => { + const fromStr = InterfaceId.fromString('0x579d6daba41b7d82'); + const fromU64 = InterfaceId.fromU64(fromStr.asU64()); + + expect(fromStr.toString()).toBe('0x579d6daba41b7d82'); + expect(fromU64.toString()).toBe('0x579d6daba41b7d82'); + expect(fromStr.asU64()).toBe(fromU64.asU64()); + }); + + test('detect Sails magic bytes', () => { + const iid = InterfaceId.fromString('0x579d6daba41b7d82'); + const header = SailsMessageHeader.v1(iid, 5, 0); + const bytes = header.toBytes(); + + const { ok, header: parsed } = SailsMessageHeader.tryFromBytes(bytes); + expect(ok).toBe(true); + expect(parsed).toBeDefined(); + expect(parsed!.entryId).toBe(5); + }); + + test('tryFromBytes fails for non-Sails bytes', () => { + const bytes = new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]); + const { ok } = SailsMessageHeader.tryFromBytes(bytes); + expect(ok).toBe(false); + }); +}); diff --git a/js/mcp-server/tests/idl-tools.test.ts b/js/mcp-server/tests/idl-tools.test.ts new file mode 100644 index 000000000..34d785ff4 --- /dev/null +++ b/js/mcp-server/tests/idl-tools.test.ts @@ -0,0 +1,90 @@ +import { describe, test, expect, beforeAll } from 'bun:test'; +import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { registry } from '../src/registry'; +import { summarizeProgram, summarizeService, summarizeFunction } from '../src/summarize'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const thisDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(thisDir, '..', '..', '..'); +// Use demo-v2 IDL which is compatible with the current parser WASM +const demoIdlPath = resolve(repoRoot, 'js/test/demo-v2/demo.idl'); + +let parser: SailsIdlParser; + +beforeAll(async () => { + parser = new SailsIdlParser(); + await parser.init(); +}); + +describe('IDL parsing', () => { + test('parse demo IDL', async () => { + const idl = await readFile(demoIdlPath, 'utf-8'); + const doc = parser.parse(idl); + + expect(doc).toBeDefined(); + expect(doc.program).toBeDefined(); + expect(doc.program!.name).toBe('DemoClient'); + expect(doc.services!.length).toBeGreaterThan(0); + }); + + test('register and summarize program', async () => { + const idl = await readFile(demoIdlPath, 'utf-8'); + const doc = parser.parse(idl); + + const entry = registry.register('DemoClient', doc); + const summary = summarizeProgram(entry); + + expect(summary.program).toBe('DemoClient'); + expect(summary.services.length).toBeGreaterThan(0); + expect(summary.constructors.length).toBe(2); // Default, New + + // Check Counter service exists + const counter = summary.services.find((s) => s.name === 'Counter'); + expect(counter).toBeDefined(); + expect(counter!.interface_id).toBe('0x579d6daba41b7d82'); + }); + + test('summarize Counter service', async () => { + const entry = registry.getOrThrow('DemoClient'); + const detail = summarizeService(entry, 'Counter'); + + expect(detail.name).toBe('Counter'); + expect(detail.interface_id).toBe('0x579d6daba41b7d82'); + expect(detail.functions.length).toBe(3); // Add, Sub, Value + expect(detail.events.length).toBe(2); // Added, Subtracted + + const addFn = detail.functions.find((f) => f.name === 'Add'); + expect(addFn).toBeDefined(); + expect(addFn!.params).toEqual([{ name: 'value', type: 'u32' }]); + expect(addFn!.return_type).toBe('u32'); + }); + + test('summarize function detail', async () => { + const entry = registry.getOrThrow('DemoClient'); + const detail = summarizeFunction(entry, 'Counter', 'Add'); + + expect(detail.name).toBe('Add'); + expect(detail.service).toBe('Counter'); + expect(detail.params).toEqual([{ name: 'value', type: 'u32' }]); + expect(detail.return_type).toBe('u32'); + expect(detail.entry_id).toBe(0); + }); + + test('validate valid IDL', () => { + const idl = ` + service Foo { + functions { + Bar() -> u32; + } + } + `; + expect(() => parser.parse(idl)).not.toThrow(); + }); + + test('validate invalid IDL', () => { + const idl = 'this is not valid IDL at all!!!'; + expect(() => parser.parse(idl)).toThrow(); + }); +}); diff --git a/js/mcp-server/tsconfig.json b/js/mcp-server/tsconfig.json new file mode 100644 index 000000000..271efa13f --- /dev/null +++ b/js/mcp-server/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "declaration": false, + "resolveJsonModule": true, + "removeComments": true, + "outDir": "./dist" + }, + "include": ["src"] +} diff --git a/package.json b/package.json index bea41dff2..69a81a3c0 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,11 @@ "js", "js/cli", "js/parser", - "js/parser-idl-v2", "js/types", "js/util", - "js/example" + "js/example", + "js/parser-idl-v2", + "js/mcp-server" ], "devDependencies": { "@eslint/js": "^9.39.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff3988fa1..3699c835b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -166,7 +166,7 @@ importers: devDependencies: '@gear-js/api': specifier: 0.44.2 - version: 0.44.2(@polkadot/api@16.4.6)(@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6))))(rxjs@7.8.2) + version: 0.44.2(@polkadot/api@16.4.6)(@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))))(rxjs@7.8.2) '@polkadot/api': specifier: 16.4.6 version: 16.4.6 @@ -180,6 +180,27 @@ importers: specifier: ^5.9.3 version: 5.9.3 + js/mcp-server: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ^1.12.1 + version: 1.29.0(zod@3.25.76) + sails-js: + specifier: workspace:* + version: link:.. + sails-js-parser-idl-v2: + specifier: workspace:* + version: link:../parser-idl-v2 + sails-js-types: + specifier: workspace:* + version: link:../types + sails-js-util: + specifier: workspace:* + version: link:../util + zod: + specifier: ^3.24.0 + version: 3.25.76 + js/parser: optionalDependencies: sails-js-types: @@ -425,6 +446,12 @@ packages: '@polkadot/wasm-crypto': ^7.5.1 rxjs: ^7.8.2 + '@hono/node-server@1.19.12': + resolution: {integrity: sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -688,6 +715,16 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1343,6 +1380,10 @@ packages: cpu: [x64] os: [win32] + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1357,9 +1398,20 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -1437,6 +1489,10 @@ packages: bn.js@5.2.3: resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1467,6 +1523,18 @@ packages: resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} engines: {node: '>=18.20'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1539,12 +1607,32 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + core-js-compat@3.48.0: resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -1580,6 +1668,10 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -1588,9 +1680,16 @@ packages: resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.302: resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} @@ -1604,13 +1703,32 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -1683,9 +1801,21 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -1698,6 +1828,16 @@ packages: resolution: {integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + express-rate-limit@8.3.2: + resolution: {integrity: sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1707,6 +1847,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -1731,6 +1874,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -1762,6 +1909,14 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -1785,10 +1940,18 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -1814,6 +1977,10 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -1826,13 +1993,25 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hono@4.12.9: + resolution: {integrity: sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==} + engines: {node: '>=16.9.0'} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -1882,6 +2061,14 @@ packages: '@types/node': optional: true + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -1916,6 +2103,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -2077,6 +2267,9 @@ packages: node-notifier: optional: true + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2102,6 +2295,12 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -2167,6 +2366,18 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -2174,6 +2385,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2215,6 +2434,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -2245,6 +2468,18 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2287,6 +2522,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2306,6 +2545,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@8.4.1: + resolution: {integrity: sha512-fvU78fIjZ+SBM9YwCknCvKOUKkLVqtWDVctl0s7xIqfmfb38t2TT4ZU2gHm+Z8xGwgW+QWEU3oQSAzIbo89Ggw==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2321,6 +2563,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -2346,6 +2592,10 @@ packages: resolution: {integrity: sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==} engines: {node: '>= 8'} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2353,6 +2603,18 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -2368,6 +2630,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -2408,6 +2674,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-async@4.0.6: resolution: {integrity: sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==} engines: {node: '>=0.12.0'} @@ -2430,6 +2700,17 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2438,6 +2719,22 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -2466,6 +2763,10 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -2533,6 +2834,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + ts-api-utils@2.4.0: resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} @@ -2599,6 +2904,10 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typescript-eslint@8.56.1: resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2623,6 +2932,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -2642,6 +2955,10 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -2719,6 +3036,14 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + snapshots: '@babel/code-frame@7.29.0': @@ -2982,6 +3307,16 @@ snapshots: '@polkadot/wasm-crypto': 7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6))) rxjs: 7.8.2 + '@gear-js/api@0.44.2(@polkadot/api@16.4.6)(@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))))(rxjs@7.8.2)': + dependencies: + '@polkadot/api': 16.4.6 + '@polkadot/wasm-crypto': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) + rxjs: 7.8.2 + + '@hono/node-server@1.19.12(hono@4.12.9)': + dependencies: + hono: 4.12.9 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -3340,6 +3675,28 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.12(hono@4.12.9) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.9 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.8.1 @@ -3605,11 +3962,23 @@ snapshots: '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)) tslib: 2.8.1 + '@polkadot/wasm-bridge@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)))': + dependencies: + '@polkadot/util': 13.5.9 + '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)) + tslib: 2.8.1 + '@polkadot/wasm-crypto-asmjs@7.5.4(@polkadot/util@13.5.6)': dependencies: '@polkadot/util': 13.5.6 tslib: 2.8.1 + '@polkadot/wasm-crypto-asmjs@7.5.4(@polkadot/util@13.5.9)': + dependencies: + '@polkadot/util': 13.5.9 + tslib: 2.8.1 + '@polkadot/wasm-crypto-init@7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)))': dependencies: '@polkadot/util': 13.5.6 @@ -3620,12 +3989,28 @@ snapshots: '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)) tslib: 2.8.1 + '@polkadot/wasm-crypto-init@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)))': + dependencies: + '@polkadot/util': 13.5.9 + '@polkadot/wasm-bridge': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) + '@polkadot/wasm-crypto-asmjs': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/wasm-crypto-wasm': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)) + tslib: 2.8.1 + '@polkadot/wasm-crypto-wasm@7.5.4(@polkadot/util@13.5.6)': dependencies: '@polkadot/util': 13.5.6 '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.6) tslib: 2.8.1 + '@polkadot/wasm-crypto-wasm@7.5.4(@polkadot/util@13.5.9)': + dependencies: + '@polkadot/util': 13.5.9 + '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) + tslib: 2.8.1 + '@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)))': dependencies: '@polkadot/util': 13.5.6 @@ -3637,11 +4022,27 @@ snapshots: '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)) tslib: 2.8.1 + '@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)))': + dependencies: + '@polkadot/util': 13.5.9 + '@polkadot/wasm-bridge': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) + '@polkadot/wasm-crypto-asmjs': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/wasm-crypto-init': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) + '@polkadot/wasm-crypto-wasm': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)) + tslib: 2.8.1 + '@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)': dependencies: '@polkadot/util': 13.5.6 tslib: 2.8.1 + '@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)': + dependencies: + '@polkadot/util': 13.5.9 + tslib: 2.8.1 + '@polkadot/x-bigint@13.5.6': dependencies: '@polkadot/x-global': 13.5.6 @@ -3673,6 +4074,13 @@ snapshots: '@polkadot/x-global': 13.5.9 tslib: 2.8.1 + '@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))': + dependencies: + '@polkadot/util': 13.5.9 + '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) + '@polkadot/x-global': 13.5.9 + tslib: 2.8.1 + '@polkadot/x-textdecoder@13.5.6': dependencies: '@polkadot/x-global': 13.5.6 @@ -4093,6 +4501,11 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -4103,6 +4516,10 @@ snapshots: acorn@8.16.0: {} + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -4110,6 +4527,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -4199,6 +4623,20 @@ snapshots: bn.js@5.2.3: {} + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -4232,6 +4670,18 @@ snapshots: builtin-modules@5.0.0: {} + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + callsites@3.1.0: {} camelcase@5.3.1: {} @@ -4283,12 +4733,25 @@ snapshots: concat-map@0.0.1: {} + content-disposition@1.0.1: {} + + content-type@1.0.5: {} + convert-source-map@2.0.0: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + core-js-compat@3.48.0: dependencies: browserslist: 4.28.1 + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + create-require@1.1.1: {} cross-spawn@7.0.6: @@ -4309,12 +4772,22 @@ snapshots: deepmerge@4.3.1: {} + depd@2.0.0: {} + detect-newline@3.1.0: {} diff@4.0.4: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} + electron-to-chromium@1.5.302: {} emittery@0.13.1: {} @@ -4323,12 +4796,24 @@ snapshots: emoji-regex@9.2.2: {} + encodeurl@2.0.0: {} + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} escape-string-regexp@2.0.0: {} @@ -4429,8 +4914,16 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + eventemitter3@5.0.4: {} + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -4454,12 +4947,52 @@ snapshots: jest-mock: 30.2.0 jest-util: 30.2.0 + express-rate-limit@8.3.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} + fast-uri@3.1.0: {} + fb-watchman@2.0.2: dependencies: bser: 2.1.1 @@ -4481,6 +5014,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-cache-dir@3.3.2: dependencies: commondir: 1.0.1 @@ -4515,6 +5059,10 @@ snapshots: dependencies: fetch-blob: 3.2.0 + forwarded@0.2.0: {} + + fresh@2.0.0: {} + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -4532,8 +5080,26 @@ snapshots: get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + get-package-type@0.1.0: {} + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-stream@6.0.1: {} glob-parent@6.0.2: @@ -4562,6 +5128,8 @@ snapshots: globals@16.5.0: {} + gopd@1.2.0: {} + graceful-fs@4.2.11: {} handlebars@4.7.8: @@ -4575,12 +5143,24 @@ snapshots: has-flag@4.0.0: {} + has-symbols@1.1.0: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 + hono@4.12.9: {} + html-escaper@2.0.2: {} + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + human-signals@2.1.0: {} iconv-lite@0.7.2: @@ -4624,6 +5204,10 @@ snapshots: optionalDependencies: '@types/node': 24.10.13 + ip-address@10.1.0: {} + + ipaddr.js@1.9.1: {} + is-arrayish@0.2.1: {} is-builtin-module@5.0.0: @@ -4648,6 +5232,8 @@ snapshots: is-number@7.0.0: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 @@ -5005,6 +5591,8 @@ snapshots: - supports-color - ts-node + jose@6.2.2: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -5024,6 +5612,10 @@ snapshots: json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + json-stable-stringify-without-jsonify@1.0.1: {} json-stringify-safe@5.0.1: {} @@ -5085,6 +5677,12 @@ snapshots: dependencies: tmpl: 1.0.5 + math-intrinsics@1.1.0: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} micromatch@4.0.8: @@ -5092,6 +5690,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mimic-fn@2.1.0: {} minimatch@10.2.2: @@ -5120,6 +5724,8 @@ snapshots: natural-compare@1.4.0: {} + negotiator@1.0.0: {} + neo-async@2.6.2: {} nock@13.5.6: @@ -5148,6 +5754,14 @@ snapshots: dependencies: path-key: 3.1.1 + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -5196,6 +5810,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parseurl@1.3.3: {} + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -5209,6 +5825,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.3 + path-to-regexp@8.4.1: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -5217,6 +5835,8 @@ snapshots: pirates@4.0.7: {} + pkce-challenge@5.0.1: {} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -5235,10 +5855,28 @@ snapshots: propagate@2.0.1: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + punycode@2.3.1: {} pure-rand@7.0.1: {} + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + react-is@18.3.1: {} regexp-tree@0.1.27: {} @@ -5249,6 +5887,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -5316,6 +5956,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.1 + transitivePeerDependencies: + - supports-color + run-async@4.0.6: {} rxjs@7.8.2: @@ -5331,12 +5981,67 @@ snapshots: semver@7.7.4: {} + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -5364,6 +6069,8 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 + statuses@2.0.2: {} + string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -5428,6 +6135,8 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -5482,6 +6191,12 @@ snapshots: type-fest@4.41.0: {} + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typescript-eslint@8.56.1(eslint@9.39.3)(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3)(typescript@5.9.3))(eslint@9.39.3)(typescript@5.9.3) @@ -5502,6 +6217,8 @@ snapshots: universalify@2.0.1: {} + unpipe@1.0.0: {} + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -5544,6 +6261,8 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + vary@1.1.2: {} + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -5606,3 +6325,9 @@ snapshots: yocto-queue@0.1.0: {} yoctocolors-cjs@2.1.3: {} + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 119c09ecc..f0ab61d6b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,6 +6,7 @@ packages: - js/util - js/example - js/parser-idl-v2 + - js/mcp-server ignoredBuiltDependencies: - unrs-resolver From 5df917488690c2b2886ed94cbaa4c6812eadf36d Mon Sep 17 00:00:00 2001 From: vobradovich Date: Wed, 1 Apr 2026 00:07:51 +0200 Subject: [PATCH 2/5] wip: abi-tools, use TypeResolver --- js/mcp-server/package.json | 5 +- js/mcp-server/src/index.ts | 2 + js/mcp-server/src/summarize.ts | 82 ++- js/mcp-server/src/tools/abi-tools.ts | 760 ++++++++++++++++++++++++++ js/mcp-server/tests/abi-tools.test.ts | 197 +++++++ js/mcp-server/tests/summarize.test.ts | 192 +++++++ js/parser-idl-v2/src/idl-v2-impls.ts | 2 + js/src/sails-idl-v2.ts | 5 + js/types/src/idl-v2-types.ts | 1 + pnpm-lock.yaml | 214 +++++--- 10 files changed, 1346 insertions(+), 114 deletions(-) create mode 100644 js/mcp-server/src/tools/abi-tools.ts create mode 100644 js/mcp-server/tests/abi-tools.test.ts create mode 100644 js/mcp-server/tests/summarize.test.ts diff --git a/js/mcp-server/package.json b/js/mcp-server/package.json index b8fa0d406..08a28688b 100644 --- a/js/mcp-server/package.json +++ b/js/mcp-server/package.json @@ -14,11 +14,12 @@ "test": "bun test" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.29.0", "sails-js": "workspace:*", "sails-js-parser-idl-v2": "workspace:*", "sails-js-types": "workspace:*", "sails-js-util": "workspace:*", - "zod": "^3.24.0" + "viem": "^2.0.0", + "zod": "^4.0.0" } } diff --git a/js/mcp-server/src/index.ts b/js/mcp-server/src/index.ts index db5aa05e8..22be024c3 100644 --- a/js/mcp-server/src/index.ts +++ b/js/mcp-server/src/index.ts @@ -8,6 +8,7 @@ import { registerCodecTools } from './tools/codec-tools.js'; import { registerHeaderTools } from './tools/header-tools.js'; import { registerTypeTools } from './tools/type-tools.js'; import { registerUtilTools } from './tools/util-tools.js'; +import { registerAbiTools } from './tools/abi-tools.js'; import { registerResources } from './resources.js'; const server = new McpServer( @@ -31,6 +32,7 @@ registerCodecTools(server); registerHeaderTools(server); registerTypeTools(server); registerUtilTools(server); +registerAbiTools(server); registerResources(server); // Initialize the WASM parser eagerly so first tool call is fast diff --git a/js/mcp-server/src/summarize.ts b/js/mcp-server/src/summarize.ts index b927f2cc8..4f948d9d6 100644 --- a/js/mcp-server/src/summarize.ts +++ b/js/mcp-server/src/summarize.ts @@ -1,5 +1,6 @@ import type { RegisteredProgram } from './registry.js'; -import type { IServiceUnit, IServiceFunc, IFuncParam, IServiceEvent, TypeDecl } from 'sails-js-types'; +import type { IServiceUnit, IServiceFunc, IFuncParam, IServiceEvent } from 'sails-js-types'; +import { TypeResolver } from 'sails-js'; function interfaceIdToString(id: any): string | null { if (!id) return null; @@ -8,48 +9,28 @@ function interfaceIdToString(id: any): string | null { return null; } -function typeDeclToString(td: TypeDecl): string { - if (!td) return 'unknown'; - if (typeof td === 'string') return td; - if ('primitive' in td) return td.primitive; - if ('optional' in td) return `Option<${typeDeclToString(td.optional)}>`; - if ('vec' in td) return `Vec<${typeDeclToString(td.vec)}>`; - if ('result' in td) return `Result<${typeDeclToString(td.result.ok)}, ${typeDeclToString(td.result.err)}>`; - if ('map' in td) return `BTreeMap<${typeDeclToString(td.map.key)}, ${typeDeclToString(td.map.value)}>`; - if ('fixedArray' in td) return `[${typeDeclToString(td.fixedArray.type)}; ${td.fixedArray.len}]`; - if ('tuple' in td) return `(${td.tuple.map(typeDeclToString).join(', ')})`; - if ('userDefined' in td) { - const name = td.userDefined.name; - if (td.userDefined.params?.length) { - return `${name}<${td.userDefined.params.map(typeDeclToString).join(', ')}>`; - } - return name; - } - return JSON.stringify(td); -} - -function summarizeParams(params: IFuncParam[]) { +function summarizeParams(params: IFuncParam[], resolver: TypeResolver) { return params.map((p) => ({ name: p.name, - type: typeDeclToString(p.type), + type: resolver.getTypeDeclString(p.type), })); } -function summarizeFunc(func: IServiceFunc, idx: number) { +function summarizeFunc(func: IServiceFunc, idx: number, resolver: TypeResolver) { const entryIdAnn = func.annotations?.find(([k]) => k === 'entry-id'); const entryId = entryIdAnn ? Number(entryIdAnn[1]) : idx; return { name: func.name, kind: func.kind ?? 'command', entry_id: entryId, - params: summarizeParams(func.params), - return_type: func.output ? typeDeclToString(func.output) : 'void', - throws: func.throws ? typeDeclToString(func.throws) : undefined, + params: summarizeParams(func.params ?? [], resolver), + return_type: func.output && func.output !== '()' ? resolver.getTypeDeclString(func.output) : 'void', + throws: func.throws ? resolver.getTypeDeclString(func.throws) : undefined, docs: func.docs?.join('\n') || undefined, }; } -function summarizeEvent(event: IServiceEvent, idx: number) { +function summarizeEvent(event: IServiceEvent, idx: number, resolver: TypeResolver) { const entryIdAnn = event.annotations?.find(([k]) => k === 'entry-id'); const entryId = entryIdAnn ? Number(entryIdAnn[1]) : idx; return { @@ -57,7 +38,7 @@ function summarizeEvent(event: IServiceEvent, idx: number) { entry_id: entryId, fields: event.fields?.map((f) => ({ name: f.name, - type: typeDeclToString(f.type), + type: resolver.getTypeDeclString(f.type), })) ?? [], docs: event.docs?.join('\n') || undefined, }; @@ -76,12 +57,13 @@ function findServiceUnit(entry: RegisteredProgram, serviceName: string): IServic export function summarizeProgram(entry: RegisteredProgram) { const doc = entry.doc; + const resolver = entry.program.typeResolver; return { program: entry.name, - constructors: doc.program?.ctors?.map((c, idx) => ({ + constructors: doc.program?.ctors?.map((c) => ({ name: c.name, - params: summarizeParams(c.params), - throws: c.throws ? typeDeclToString(c.throws) : undefined, + params: summarizeParams(c.params ?? [], resolver), + throws: c.throws ? resolver.getTypeDeclString(c.throws) : undefined, docs: c.docs?.join('\n') || undefined, })) ?? [], services: doc.program?.services?.map((expo) => { @@ -101,15 +83,33 @@ export function summarizeProgram(entry: RegisteredProgram) { export function summarizeService(entry: RegisteredProgram, serviceName: string) { const unit = findServiceUnit(entry, serviceName); + const resolver = entry.program.services[serviceName].typeResolver; return { name: unit.name, interface_id: interfaceIdToString(unit.interface_id), - functions: unit.funcs?.map(summarizeFunc) ?? [], - events: unit.events?.map(summarizeEvent) ?? [], - types: unit.types?.map((t) => ({ - name: t.name, - def: t.def, - })) ?? [], + functions: unit.funcs?.map((f, i) => summarizeFunc(f, i, resolver)) ?? [], + events: unit.events?.map((e, i) => summarizeEvent(e, i, resolver)) ?? [], + types: unit.types?.map((t) => { + if (t.kind === 'struct') { + return { + name: t.name, + kind: 'struct', + fields: t.fields.map((f) => ({ name: f.name, type: resolver.getTypeDeclString(f.type) })), + }; + } else if (t.kind === 'enum') { + return { + name: t.name, + kind: 'enum', + variants: t.variants.map((v) => v.name), + }; + } else { + return { + name: t.name, + kind: 'alias', + target: resolver.getTypeDeclString(t.target), + }; + } + }) ?? [], extends: unit.extends?.map((e) => ({ name: e.name, interface_id: interfaceIdToString(e.interface_id), @@ -124,6 +124,7 @@ export function summarizeFunction( funcName: string, ) { const unit = findServiceUnit(entry, serviceName); + const resolver = entry.program.services[serviceName].typeResolver; const allFuncs = unit.funcs ?? []; const idx = allFuncs.findIndex((f) => f.name === funcName); if (idx === -1) { @@ -133,11 +134,8 @@ export function summarizeFunction( ); } const func = allFuncs[idx]; - const detail = summarizeFunc(func, idx); - - // Also include the service context return { - ...detail, + ...summarizeFunc(func, idx, resolver), service: serviceName, interface_id: interfaceIdToString(unit.interface_id), }; diff --git a/js/mcp-server/src/tools/abi-tools.ts b/js/mcp-server/src/tools/abi-tools.ts new file mode 100644 index 000000000..6a2b21fda --- /dev/null +++ b/js/mcp-server/src/tools/abi-tools.ts @@ -0,0 +1,760 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { z } from 'zod'; +import { + encodeAbiParameters, + decodeAbiParameters, + keccak256, + toHex, + type AbiParameter, +} from 'viem'; +import { registry } from '../registry.js'; +import type { TypeDecl, IIdlDoc, IServiceUnit, IServiceFunc, IStructField } from 'sails-js-types'; + +// --------------------------------------------------------------------------- +// Type mapping: IDL TypeDecl → Solidity type string +// Based on rs/sol-gen/src/typedecl_to_sol.rs +// --------------------------------------------------------------------------- + +export function typeDeclToSolidity(td: TypeDecl): string { + if (typeof td === 'string') { + switch (td) { + case 'bool': return 'bool'; + case 'u8': return 'uint8'; + case 'u16': return 'uint16'; + case 'u32': return 'uint32'; + case 'u64': return 'uint64'; + case 'u128': return 'uint128'; + case 'U256': return 'uint256'; + case 'i8': return 'int8'; + case 'i16': return 'int16'; + case 'i32': return 'int32'; + case 'i64': return 'int64'; + case 'i128': return 'int128'; + case 'String': return 'string'; + case 'ActorId': return 'address'; + case 'H256': + case 'CodeId': + case 'MessageId': return 'bytes32'; + case 'H160': return 'bytes20'; + case '()': throw new Error('Void type () has no Solidity representation'); + case 'char': throw new Error('char type is not supported in Solidity ABI'); + default: throw new Error(`Unsupported primitive type in ABI: ${td}`); + } + } + if (td.kind === 'slice') { + return `${typeDeclToSolidity(td.item)}[]`; + } + if (td.kind === 'array') { + return `${typeDeclToSolidity(td.item)}[${td.len}]`; + } + if (td.kind === 'tuple') { + throw new Error('Tuple types are not supported in Sails ABI encoding'); + } + if (td.kind === 'named') { + throw new Error( + `Named type "${td.name}" is not supported in Sails ABI encoding. ` + + 'Only primitives, slices, and fixed arrays are allowed.', + ); + } + throw new Error(`Unknown TypeDecl: ${JSON.stringify(td)}`); +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function toAbiParam(name: string, type: TypeDecl): AbiParameter { + return { name, type: typeDeclToSolidity(type) } as AbiParameter; +} + +/** camelCase(serviceName + funcName): "Counter" + "Add" → "counterAdd" */ +function solFuncName(serviceName: string, funcName: string): string { + const combined = serviceName + funcName; + return combined[0].toLowerCase() + combined.slice(1); +} + +/** Build a Solidity-style signature string, e.g. "counterAdd(bool,uint32)" */ +function buildSignature(name: string, paramTypes: string[]): string { + return `${name}(${paramTypes.join(',')})`; +} + +/** Compute the 4-byte Solidity selector from a signature string */ +function computeSelector(sig: string): `0x${string}` { + const hash = keccak256(toHex(sig)); + return hash.slice(0, 10) as `0x${string}`; +} + +function getServiceUnit(entry: ReturnType, serviceName: string): IServiceUnit { + const unit = entry.doc.services?.find((s) => s.name === serviceName); + if (!unit) { + const available = entry.doc.services?.map((s) => s.name) ?? []; + throw new Error(`Service "${serviceName}" not found. Available: [${available.join(', ')}]`); + } + return unit; +} + +function getIdlFunc( + entry: ReturnType, + serviceName: string, + funcName: string, +): IServiceFunc { + const unit = getServiceUnit(entry, serviceName); + const func = unit.funcs?.find((f) => f.name === funcName); + if (!func) { + const available = unit.funcs?.map((f) => f.name) ?? []; + throw new Error( + `Function "${funcName}" not found in service "${serviceName}". Available: [${available.join(', ')}]`, + ); + } + return func; +} + +function isPayable(func: IServiceFunc): boolean { + return func.docs?.some((d) => d.includes('#[payable]')) ?? false; +} + +function isReturnsValue(func: IServiceFunc): boolean { + return func.docs?.some((d) => d.includes('#[returns_value]')) ?? false; +} + +function isIndexed(field: IStructField): boolean { + return field.docs?.some((d) => d.includes('#[indexed]')) ?? false; +} + +// --------------------------------------------------------------------------- +// Solidity contract generation +// Based on rs/sol-gen/src/hbs/contract.hbs and rs/sol-gen/src/lib.rs +// --------------------------------------------------------------------------- + +function generateSolidity(doc: IIdlDoc, baseName: string): string { + const services = doc.services ?? []; + const lines: string[] = []; + + lines.push('// SPDX-License-Identifier: UNLICENSED'); + lines.push('pragma solidity ^0.8.26;'); + lines.push(''); + + // Contract 1: Interface + lines.push(`interface I${baseName} {`); + for (const unit of services) { + for (const func of unit.funcs ?? []) { + const solName = solFuncName(unit.name, func.name); + const payableKw = isPayable(func) ? ' payable' : ''; + const paramList = [ + 'bool _callReply', + ...(func.params ?? []).map((p) => `${typeDeclToSolidity(p.type)} ${p.name}`), + ].join(', '); + const hasOutput = func.output && func.output !== '()'; + const returnType = hasOutput ? typeDeclToSolidity(func.output) : null; + + lines.push( + ` function ${solName}(${paramList}) external${payableKw} returns (bytes32 messageId);`, + ); + // Additional overload for #[returns_value] + if (isReturnsValue(func) && returnType) { + lines.push( + ` function ${solName}(${paramList}, bool returns_value) external${payableKw} returns (bytes32 messageId, ${returnType} result);`, + ); + } + } + // Events + for (const event of unit.events ?? []) { + const fieldList = (event.fields ?? []) + .map((f, i) => { + const solType = typeDeclToSolidity(f.type); + const indexed = isIndexed(f) ? ' indexed' : ''; + return `${solType}${indexed} ${f.name ?? `field${i}`}`; + }) + .join(', '); + lines.push(` event ${event.name}(${fieldList});`); + } + } + lines.push('}'); + lines.push(''); + + // Contract 2: Abi (pure selector functions) + lines.push(`abstract contract ${baseName}Abi {`); + for (const unit of services) { + for (const func of unit.funcs ?? []) { + const solName = solFuncName(unit.name, func.name); + const paramTypes = [ + 'bool', + ...(func.params ?? []).map((p) => typeDeclToSolidity(p.type)), + ]; + const sig = buildSignature(solName, paramTypes); + lines.push(` function ${solName}_sig() public pure returns (bytes4) {`); + lines.push(` return bytes4(keccak256("${sig}"));`); + lines.push(` }`); + } + } + lines.push('}'); + lines.push(''); + + // Contract 3: Callbacks interface + lines.push(`interface I${baseName}Callbacks {`); + for (const unit of services) { + for (const func of unit.funcs ?? []) { + if (func.output && func.output !== '()') { + const solName = solFuncName(unit.name, func.name); + const returnType = typeDeclToSolidity(func.output); + lines.push(` function replyOn_${solName}(${returnType} result) external;`); + } + } + } + lines.push('}'); + lines.push(''); + + // Contract 4: Caller (abstract helper) + lines.push(`abstract contract ${baseName}Caller {`); + lines.push(` address public immutable program;`); + lines.push(` constructor(address _program) { program = _program; }`); + lines.push(''); + for (const unit of services) { + for (const func of unit.funcs ?? []) { + const solName = solFuncName(unit.name, func.name); + const payableKw = isPayable(func) ? ' payable' : ''; + const paramList = (func.params ?? []) + .map((p) => `${typeDeclToSolidity(p.type)} ${p.name}`) + .join(', '); + const passArgs = (func.params ?? []).map((p) => p.name).join(', '); + const callArgs = passArgs ? `false, ${passArgs}` : 'false'; + lines.push( + ` function ${solName}(${paramList}) internal${payableKw} returns (bytes32 messageId) {`, + ); + lines.push(` return I${baseName}(program).${solName}(${callArgs});`); + lines.push(` }`); + } + } + lines.push('}'); + + return lines.join('\n'); +} + +// --------------------------------------------------------------------------- +// Tool registration +// --------------------------------------------------------------------------- + +export function registerAbiTools(server: McpServer) { + server.registerTool( + 'sails_type_to_solidity', + { + description: + 'Map an IDL type to its Solidity equivalent. ' + + 'Supported: bool, u8-u128, U256, i8-i128, String→string, ActorId→address, ' + + 'H256/CodeId/MessageId→bytes32, H160→bytes20, slices→T[], fixed arrays→T[N]. ' + + 'Pass a primitive name (e.g. "u32") or a JSON TypeDecl object.', + inputSchema: { + type_decl: z + .string() + .describe('IDL type: a primitive name like "u32" or JSON like {"kind":"slice","item":"u8"}'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ type_decl }) => { + try { + let td: TypeDecl; + try { + td = JSON.parse(type_decl) as TypeDecl; + } catch { + td = type_decl as TypeDecl; + } + const solType = typeDeclToSolidity(td); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ idl_type: type_decl, solidity_type: solType }, null, 2), + }, + ], + }; + } catch (err: any) { + return { isError: true, content: [{ type: 'text', text: err.message }] }; + } + }, + ); + + server.registerTool( + 'sails_solidity_signature', + { + description: + 'Compute the Solidity function/event signature and 4-byte selector for an IDL function or event. ' + + 'Functions include the implicit bool _callReply first param. ' + + 'Function names follow ethexe convention: camelCase(ServiceName + FunctionName).', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + name: z.string().describe('Function or event name'), + kind: z + .enum(['function', 'event']) + .default('function') + .describe('Whether to compute selector for a function or event'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, name: targetName, kind }) => { + try { + const entry = registry.getOrThrow(programName); + const unit = getServiceUnit(entry, serviceName); + + if (kind === 'function') { + const func = unit.funcs?.find((f) => f.name === targetName); + if (!func) { + throw new Error(`Function "${targetName}" not found in service "${serviceName}"`); + } + const solName = solFuncName(serviceName, targetName); + const paramTypes = [ + 'bool', + ...(func.params ?? []).map((p) => typeDeclToSolidity(p.type)), + ]; + const sig = buildSignature(solName, paramTypes); + const sel = computeSelector(sig); + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { signature: sig, selector: sel, solidity_name: solName, payable: isPayable(func) }, + null, + 2, + ), + }, + ], + }; + } else { + const event = unit.events?.find((e) => e.name === targetName); + if (!event) { + throw new Error(`Event "${targetName}" not found in service "${serviceName}"`); + } + const fieldTypes = (event.fields ?? []).map((f) => typeDeclToSolidity(f.type)); + const sig = buildSignature(targetName, fieldTypes); + const sel = computeSelector(sig); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ signature: sig, selector: sel }, null, 2), + }, + ], + }; + } + } catch (err: any) { + return { isError: true, content: [{ type: 'text', text: err.message }] }; + } + }, + ); + + server.registerTool( + 'sails_abi_encode_call', + { + description: + 'ABI-encode an ethexe function call: 4-byte selector + ABI-encoded params. ' + + 'Automatically prepends the implicit bool _callReply first param. ' + + 'Function selector uses camelCase(ServiceName+FunctionName) naming. ' + + 'For u64/u128/U256 values pass numeric strings to avoid JS integer overflow.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + function: z.string().describe('Function name'), + args: z + .array(z.any()) + .default([]) + .describe('Function args as JSON array in parameter order (excluding _callReply)'), + call_reply: z + .boolean() + .default(false) + .describe('Value for the implicit bool _callReply first param'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, function: funcName, args, call_reply }) => { + try { + const entry = registry.getOrThrow(programName); + const func = getIdlFunc(entry, serviceName, funcName); + const solName = solFuncName(serviceName, funcName); + const paramTypes = [ + 'bool', + ...(func.params ?? []).map((p) => typeDeclToSolidity(p.type)), + ]; + const sig = buildSignature(solName, paramTypes); + const sel = computeSelector(sig); + + const abiParams: AbiParameter[] = [ + { name: '_callReply', type: 'bool' }, + ...(func.params ?? []).map((p) => toAbiParam(p.name, p.type)), + ]; + const encoded = encodeAbiParameters(abiParams, [call_reply, ...args]); + const hex = (sel + encoded.slice(2)) as `0x${string}`; + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + hex, + selector: sel, + signature: sig, + payable: isPayable(func), + explanation: `${sel} (selector) + ABI-encoded(_callReply=${call_reply}, ${(func.params ?? []) + .map((p, i) => `${p.name}=${JSON.stringify(args[i] ?? null)}`) + .join(', ')})`, + }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `ABI encode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_abi_decode_call', + { + description: + 'ABI-decode a hex payload by matching the first 4 bytes (selector) against all known functions in a program. ' + + 'Returns the matched service/function name and decoded arguments.', + inputSchema: { + program: z.string().describe('Registered program name'), + hex: z.string().describe('Hex-encoded payload (4-byte selector + ABI-encoded params)'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, hex: hexInput }) => { + try { + const entry = registry.getOrThrow(programName); + const normalized = hexInput.startsWith('0x') ? hexInput : `0x${hexInput}`; + const callSelector = normalized.slice(0, 10).toLowerCase(); + + for (const unit of entry.doc.services ?? []) { + for (const func of unit.funcs ?? []) { + let paramTypes: string[]; + try { + paramTypes = [ + 'bool', + ...(func.params ?? []).map((p) => typeDeclToSolidity(p.type)), + ]; + } catch { + continue; // skip functions with unsupported types + } + const sig = buildSignature(solFuncName(unit.name, func.name), paramTypes); + const sel = computeSelector(sig); + + if (sel.toLowerCase() === callSelector) { + const abiParams: AbiParameter[] = [ + { name: '_callReply', type: 'bool' }, + ...(func.params ?? []).map((p) => toAbiParam(p.name, p.type)), + ]; + const decoded = decodeAbiParameters( + abiParams, + `0x${normalized.slice(10)}` as `0x${string}`, + ); + const [callReply, ...funcArgs] = decoded; + const argsObj: Record = {}; + (func.params ?? []).forEach((p, i) => { + argsObj[p.name] = funcArgs[i]; + }); + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + service: unit.name, + function: func.name, + selector: sel, + _callReply: callReply, + args: argsObj, + }, + null, + 2, + ), + }, + ], + }; + } + } + } + throw new Error( + `No function matches selector ${callSelector} in program "${programName}"`, + ); + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `ABI decode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_abi_decode_result', + { + description: + 'ABI-decode a function reply from hex. ' + + 'Decodes the return value according to the IDL function output type.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + function: z.string().describe('Function name'), + hex: z.string().describe('Hex-encoded ABI result payload'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, function: funcName, hex: hexInput }) => { + try { + const entry = registry.getOrThrow(programName); + const func = getIdlFunc(entry, serviceName, funcName); + + if (!func.output || func.output === '()') { + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { result: null, note: 'Function returns void' }, + null, + 2, + ), + }, + ], + }; + } + + const returnType = typeDeclToSolidity(func.output); + const normalized = ( + hexInput.startsWith('0x') ? hexInput : `0x${hexInput}` + ) as `0x${string}`; + const decoded = decodeAbiParameters([{ name: 'result', type: returnType }], normalized); + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { service: serviceName, function: funcName, result: decoded[0] }, + null, + 2, + ), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `ABI decode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_abi_encode_event', + { + description: + 'ABI-encode an ethexe event into topics and data. ' + + 'topics[0] = keccak256 event signature hash. ' + + 'Fields marked #[indexed] in IDL become additional topics; non-indexed fields are ABI-encoded as data.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + event: z.string().describe('Event name'), + fields: z + .record(z.any()) + .describe('Event field values as a JSON object { fieldName: value }'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, event: eventName, fields }) => { + try { + const entry = registry.getOrThrow(programName); + const unit = getServiceUnit(entry, serviceName); + const event = unit.events?.find((e) => e.name === eventName); + if (!event) { + throw new Error(`Event "${eventName}" not found in service "${serviceName}"`); + } + + const allFields = event.fields ?? []; + const indexedFields = allFields.filter(isIndexed); + const dataFields = allFields.filter((f) => !isIndexed(f)); + + // Event signature hash → topic[0] + const fieldTypes = allFields.map((f) => typeDeclToSolidity(f.type)); + const sig = buildSignature(eventName, fieldTypes); + const eventTopic = keccak256(toHex(sig)); + + // Indexed fields → additional topics (ABI-encode each as 32 bytes) + const topics: string[] = [eventTopic]; + for (const field of indexedFields) { + const solType = typeDeclToSolidity(field.type); + const val = fields[field.name ?? '']; + const encoded = encodeAbiParameters([{ name: field.name ?? '', type: solType }], [val]); + // Take the last 32 bytes (64 hex chars) as topic + topics.push(`0x${encoded.slice(2).slice(-64).padStart(64, '0')}`); + } + + // Non-indexed fields → data + let data: string = '0x'; + if (dataFields.length > 0) { + const dataParams: AbiParameter[] = dataFields.map((f) => + toAbiParam(f.name ?? '', f.type), + ); + const dataValues = dataFields.map((f) => fields[f.name ?? '']); + data = encodeAbiParameters(dataParams, dataValues); + } + + return { + content: [ + { + type: 'text', + text: JSON.stringify({ event: eventName, signature: sig, topics, data }, null, 2), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `ABI event encode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_abi_decode_event', + { + description: + 'ABI-decode an ethexe event from topics and data. ' + + 'Matches topics[0] (event signature hash) to identify the event if event name is omitted.', + inputSchema: { + program: z.string().describe('Registered program name'), + service: z.string().describe('Service name'), + topics: z + .array(z.string()) + .describe('Hex topic strings; topics[0] is the event signature hash'), + data: z.string().default('0x').describe('Hex-encoded ABI data for non-indexed fields'), + event: z + .string() + .optional() + .describe('Event name. If omitted, auto-detects from topics[0].'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, service: serviceName, topics, data, event: eventName }) => { + try { + const entry = registry.getOrThrow(programName); + const unit = getServiceUnit(entry, serviceName); + + let targetEvent = unit.events?.find((e) => e.name === eventName); + if (!targetEvent && eventName) { + throw new Error(`Event "${eventName}" not found in service "${serviceName}"`); + } + + if (!targetEvent) { + const topic0 = (topics[0] ?? '').toLowerCase(); + for (const ev of unit.events ?? []) { + const fieldTypes = (ev.fields ?? []).map((f) => typeDeclToSolidity(f.type)); + const sig = buildSignature(ev.name, fieldTypes); + if (keccak256(toHex(sig)).toLowerCase() === topic0) { + targetEvent = ev; + break; + } + } + if (!targetEvent) { + throw new Error( + `No event in service "${serviceName}" matches topics[0]=${topics[0]}`, + ); + } + } + + const allFields = targetEvent.fields ?? []; + const indexedFields = allFields.filter(isIndexed); + const dataFields = allFields.filter((f) => !isIndexed(f)); + const result: Record = {}; + + // Decode indexed fields from topics[1..] + indexedFields.forEach((field, i) => { + const topic = topics[i + 1]; + if (topic) { + const solType = typeDeclToSolidity(field.type); + const padded = topic.startsWith('0x') ? topic : `0x${topic}`; + // Pad to 32 bytes for decoding + const padded32 = `0x${padded.slice(2).padStart(64, '0')}` as `0x${string}`; + const decoded = decodeAbiParameters( + [{ name: field.name ?? '', type: solType }], + padded32, + ); + result[field.name ?? `indexed_${i}`] = decoded[0]; + } + }); + + // Decode non-indexed from data + if (dataFields.length > 0 && data && data !== '0x') { + const dataParams: AbiParameter[] = dataFields.map((f) => + toAbiParam(f.name ?? '', f.type), + ); + const decoded = decodeAbiParameters(dataParams, data as `0x${string}`); + dataFields.forEach((f, i) => { + result[f.name ?? `data_${i}`] = decoded[i]; + }); + } + + return { + content: [ + { + type: 'text', + text: JSON.stringify({ event: targetEvent.name, fields: result }, null, 2), + }, + ], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `ABI event decode error: ${err.message}` }], + }; + } + }, + ); + + server.registerTool( + 'sails_generate_solidity', + { + description: + 'Generate a Solidity interface from a registered IDL program. ' + + 'Produces 4 contracts: I{Name} (interface), {Name}Abi (selectors), ' + + 'I{Name}Callbacks (reply callbacks), {Name}Caller (abstract caller). ' + + 'Ethexe-compatible: functions have implicit bool _callReply first param, ' + + 'payable detection from #[payable], returns_value from #[returns_value].', + inputSchema: { + program: z.string().describe('Registered program name'), + contract_name: z + .string() + .optional() + .describe('Base name for generated contracts (defaults to program name)'), + }, + annotations: { readOnlyHint: true }, + }, + async ({ program: programName, contract_name }) => { + try { + const entry = registry.getOrThrow(programName); + const baseName = contract_name ?? entry.doc.program?.name ?? programName; + const solidity = generateSolidity(entry.doc, baseName); + return { + content: [{ type: 'text', text: solidity }], + }; + } catch (err: any) { + return { + isError: true, + content: [{ type: 'text', text: `Solidity generation error: ${err.message}` }], + }; + } + }, + ); +} diff --git a/js/mcp-server/tests/abi-tools.test.ts b/js/mcp-server/tests/abi-tools.test.ts new file mode 100644 index 000000000..dd7af5b18 --- /dev/null +++ b/js/mcp-server/tests/abi-tools.test.ts @@ -0,0 +1,197 @@ +import { describe, test, expect, beforeAll } from 'bun:test'; +import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { registry } from '../src/registry'; +import { typeDeclToSolidity } from '../src/tools/abi-tools'; +import { + encodeAbiParameters, + decodeAbiParameters, + keccak256, + toHex, + type AbiParameter, +} from 'viem'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const thisDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(thisDir, '..', '..', '..'); +const demoIdlPath = resolve(repoRoot, 'js/test/demo-v2/demo.idl'); + +beforeAll(async () => { + const parser = new SailsIdlParser(); + await parser.init(); + const idl = await readFile(demoIdlPath, 'utf-8'); + const doc = parser.parse(idl); + registry.register('DemoClient', doc); +}); + +// --------------------------------------------------------------------------- +// Type mapping +// --------------------------------------------------------------------------- + +describe('typeDeclToSolidity', () => { + test('primitive types', () => { + expect(typeDeclToSolidity('bool')).toBe('bool'); + expect(typeDeclToSolidity('u8')).toBe('uint8'); + expect(typeDeclToSolidity('u16')).toBe('uint16'); + expect(typeDeclToSolidity('u32')).toBe('uint32'); + expect(typeDeclToSolidity('u64')).toBe('uint64'); + expect(typeDeclToSolidity('u128')).toBe('uint128'); + expect(typeDeclToSolidity('U256')).toBe('uint256'); + expect(typeDeclToSolidity('i8')).toBe('int8'); + expect(typeDeclToSolidity('i32')).toBe('int32'); + expect(typeDeclToSolidity('i128')).toBe('int128'); + expect(typeDeclToSolidity('String')).toBe('string'); + expect(typeDeclToSolidity('ActorId')).toBe('address'); + expect(typeDeclToSolidity('H256')).toBe('bytes32'); + expect(typeDeclToSolidity('CodeId')).toBe('bytes32'); + expect(typeDeclToSolidity('MessageId')).toBe('bytes32'); + expect(typeDeclToSolidity('H160')).toBe('bytes20'); + }); + + test('slice type', () => { + expect(typeDeclToSolidity({ kind: 'slice', item: 'u8' })).toBe('uint8[]'); + expect(typeDeclToSolidity({ kind: 'slice', item: 'ActorId' })).toBe('address[]'); + }); + + test('fixed array type', () => { + expect(typeDeclToSolidity({ kind: 'array', item: 'u8', len: 32 })).toBe('uint8[32]'); + expect(typeDeclToSolidity({ kind: 'array', item: 'u32', len: 4 })).toBe('uint32[4]'); + }); + + test('void type throws', () => { + expect(() => typeDeclToSolidity('()')).toThrow(); + }); + + test('named type throws', () => { + expect(() => typeDeclToSolidity({ kind: 'named', name: 'MyStruct' })).toThrow(); + }); + + test('tuple type throws', () => { + expect(() => typeDeclToSolidity({ kind: 'tuple', types: ['u32', 'u64'] })).toThrow(); + }); +}); + +// --------------------------------------------------------------------------- +// Selector computation +// --------------------------------------------------------------------------- + +describe('selector computation', () => { + test('selector matches keccak256 of signature', () => { + // counterAdd(bool,uint32) - camelCase("Counter" + "Add") = "counterAdd" + const sig = 'counterAdd(bool,uint32)'; + const expected = keccak256(toHex(sig)).slice(0, 10); + // Verify it's 4 bytes = 10 chars with 0x prefix + expect(expected.length).toBe(10); + expect(expected.startsWith('0x')).toBe(true); + }); + + test('selector differs between functions', () => { + const sig1 = keccak256(toHex('counterAdd(bool,uint32)')).slice(0, 10); + const sig2 = keccak256(toHex('counterSub(bool,uint32)')).slice(0, 10); + expect(sig1).not.toBe(sig2); + }); +}); + +// --------------------------------------------------------------------------- +// ABI encode/decode round-trips (using viem directly) +// --------------------------------------------------------------------------- + +describe('ABI encode/decode round-trips', () => { + test('encode and decode counterAdd call', () => { + // counterAdd(bool _callReply, uint32 value) + const params: AbiParameter[] = [ + { name: '_callReply', type: 'bool' }, + { name: 'value', type: 'uint32' }, + ]; + const encoded = encodeAbiParameters(params, [false, 42]); + const decoded = decodeAbiParameters(params, encoded); + + expect(decoded[0]).toBe(false); + expect(decoded[1]).toBe(42); + }); + + test('encode and decode with address param', () => { + const params: AbiParameter[] = [ + { name: '_callReply', type: 'bool' }, + { name: 'actor', type: 'address' }, + ]; + const addr = '0x1234567890abcdef1234567890abcdef12345678'; + const encoded = encodeAbiParameters(params, [false, addr]); + const decoded = decodeAbiParameters(params, encoded); + expect(decoded[1].toLowerCase()).toBe(addr.toLowerCase()); + }); + + test('encode and decode with bytes32 param', () => { + const params: AbiParameter[] = [{ name: 'hash', type: 'bytes32' }]; + const h256 = '0x' + 'ab'.repeat(32); + const encoded = encodeAbiParameters(params, [h256]); + const decoded = decodeAbiParameters(params, encoded); + expect((decoded[0] as string).toLowerCase()).toBe(h256.toLowerCase()); + }); + + test('encode and decode with string param', () => { + const params: AbiParameter[] = [ + { name: '_callReply', type: 'bool' }, + { name: 'input', type: 'string' }, + ]; + const encoded = encodeAbiParameters(params, [false, 'hello world']); + const decoded = decodeAbiParameters(params, encoded); + expect(decoded[1]).toBe('hello world'); + }); +}); + +// --------------------------------------------------------------------------- +// Event signature hashing +// --------------------------------------------------------------------------- + +describe('event topic computation', () => { + test('event topic is keccak256 of signature', () => { + // Hypothetical event: Transfer(address,address,uint256) + const sig = 'Transfer(address,address,uint256)'; + const topic = keccak256(toHex(sig)); + expect(topic.length).toBe(66); // 0x + 64 hex chars + expect(topic.startsWith('0x')).toBe(true); + }); + + test('different event signatures produce different topics', () => { + const t1 = keccak256(toHex('Added(uint32)')); + const t2 = keccak256(toHex('Subtracted(uint32)')); + expect(t1).not.toBe(t2); + }); +}); + +// --------------------------------------------------------------------------- +// Solidity generation (smoke test via IDL doc inspection) +// --------------------------------------------------------------------------- + +describe('Solidity generation', () => { + test('demo IDL has Counter service with ABI-compatible types', () => { + const entry = registry.getOrThrow('DemoClient'); + const counterUnit = entry.doc.services?.find((s) => s.name === 'Counter'); + expect(counterUnit).toBeDefined(); + + // All Counter function params should map to Solidity without error + for (const func of counterUnit!.funcs ?? []) { + for (const param of func.params ?? []) { + expect(() => typeDeclToSolidity(param.type)).not.toThrow(); + } + // output type (except void) + if (func.output && func.output !== '()') { + expect(() => typeDeclToSolidity(func.output)).not.toThrow(); + } + } + }); + + test('function naming convention: camelCase(Service + Func)', () => { + // "Counter" + "Add" → "counterAdd" + const combined = 'Counter' + 'Add'; + const solName = combined[0].toLowerCase() + combined.slice(1); + expect(solName).toBe('counterAdd'); + + // "PingPong" + "Ping" → "pingPongPing" + const combined2 = 'PingPong' + 'Ping'; + const solName2 = combined2[0].toLowerCase() + combined2.slice(1); + expect(solName2).toBe('pingPongPing'); + }); +}); diff --git a/js/mcp-server/tests/summarize.test.ts b/js/mcp-server/tests/summarize.test.ts new file mode 100644 index 000000000..30adb3bc8 --- /dev/null +++ b/js/mcp-server/tests/summarize.test.ts @@ -0,0 +1,192 @@ +import { describe, test, expect, beforeAll } from 'bun:test'; +import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { registry } from '../src/registry'; +import { summarizeProgram, summarizeService, summarizeFunction } from '../src/summarize'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const thisDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(thisDir, '..', '..', '..'); +const demoIdlPath = resolve(repoRoot, 'js/test/demo-v2/demo.idl'); + +const PROGRAM = 'SummarizeDemo'; + +beforeAll(async () => { + const parser = new SailsIdlParser(); + await parser.init(); + const idl = await readFile(demoIdlPath, 'utf-8'); + const doc = parser.parse(idl); + registry.register(PROGRAM, doc); +}); + +// --------------------------------------------------------------------------- +// summarizeProgram +// --------------------------------------------------------------------------- + +describe('summarizeProgram', () => { + test('returns program name', () => { + const summary = summarizeProgram(registry.getOrThrow(PROGRAM)); + expect(summary.program).toBe(PROGRAM); + }); + + test('lists all services', () => { + const { services } = summarizeProgram(registry.getOrThrow(PROGRAM)); + const names = services.map((s) => s.name); + expect(names).toContain('Counter'); + expect(names).toContain('Dog'); + expect(names).toContain('ThisThat'); + }); + + test('service entry has interface_id, route_idx, function_count, event_count', () => { + const { services } = summarizeProgram(registry.getOrThrow(PROGRAM)); + const counter = services.find((s) => s.name === 'Counter')!; + expect(counter.interface_id).toBe('0x579d6daba41b7d82'); + expect(typeof counter.route_idx).toBe('number'); + expect(counter.function_count).toBeGreaterThan(0); + expect(counter.event_count).toBeGreaterThan(0); + }); + + test('lists constructors', () => { + const { constructors } = summarizeProgram(registry.getOrThrow(PROGRAM)); + const names = constructors.map((c) => c.name); + expect(names).toContain('Default'); + expect(names).toContain('New'); + }); + + test('constructor params are resolved', () => { + const { constructors } = summarizeProgram(registry.getOrThrow(PROGRAM)); + const ctor = constructors.find((c) => c.name === 'New')!; + expect(ctor.params).toHaveLength(2); + expect(ctor.params[0]).toEqual({ name: 'counter', type: 'Option' }); + expect(ctor.params[1].name).toBe('dog_position'); + }); + + test('type_count sums types across services', () => { + const { type_count } = summarizeProgram(registry.getOrThrow(PROGRAM)); + // ThisThat has 5 types, References has 1 — at minimum 6 + expect(type_count).toBeGreaterThanOrEqual(6); + }); +}); + +// --------------------------------------------------------------------------- +// summarizeService +// --------------------------------------------------------------------------- + +describe('summarizeService', () => { + test('Counter: functions and events', () => { + const detail = summarizeService(registry.getOrThrow(PROGRAM), 'Counter'); + expect(detail.name).toBe('Counter'); + expect(detail.interface_id).toBe('0x579d6daba41b7d82'); + expect(detail.functions.map((f) => f.name)).toEqual( + expect.arrayContaining(['Add', 'Sub', 'Value']), + ); + expect(detail.events.map((e) => e.name)).toEqual( + expect.arrayContaining(['Added', 'Subtracted']), + ); + }); + + test('function params and return_type resolved via TypeResolver', () => { + const { functions } = summarizeService(registry.getOrThrow(PROGRAM), 'Counter'); + const add = functions.find((f) => f.name === 'Add')!; + expect(add.params).toEqual([{ name: 'value', type: 'u32' }]); + expect(add.return_type).toBe('u32'); + expect(add.kind).toBe('command'); + }); + + test('void return_type reported as "void"', () => { + const { functions } = summarizeService(registry.getOrThrow(PROGRAM), 'ThisThat'); + const noop = functions.find((f) => f.name === 'Noop')!; + expect(noop.return_type).toBe('void'); + }); + + test('event fields are resolved', () => { + const { events } = summarizeService(registry.getOrThrow(PROGRAM), 'Counter'); + const added = events.find((e) => e.name === 'Added')!; + expect(added.fields.length).toBeGreaterThan(0); + expect(added.fields[0].type).toBeTruthy(); + }); + + test('query kind is reported', () => { + const { functions } = summarizeService(registry.getOrThrow(PROGRAM), 'Counter'); + const value = functions.find((f) => f.name === 'Value')!; + expect(value.kind).toBe('query'); + }); + + test('ThisThat: struct type is expanded with typed fields', () => { + const { types } = summarizeService(registry.getOrThrow(PROGRAM), 'ThisThat'); + const doThatParam = types.find((t) => t.name === 'DoThatParam')!; + expect(doThatParam).toBeDefined(); + expect(doThatParam.kind).toBe('struct'); + // TypeResolver resolves named types to their underlying representation + const fields = (doThatParam as any).fields as { name: string; type: string }[]; + expect(fields.find((f) => f.name === 'p3')?.type).toBe('ManyVariants'); + }); + + test('ThisThat: enum type lists variant names', () => { + const { types } = summarizeService(registry.getOrThrow(PROGRAM), 'ThisThat'); + const manyVariants = types.find((t) => t.name === 'ManyVariants')!; + expect(manyVariants.kind).toBe('enum'); + expect((manyVariants as any).variants).toEqual( + expect.arrayContaining(['One', 'Two', 'Three', 'Four', 'Five', 'Six']), + ); + }); + + test('References: struct alias type', () => { + const { types } = summarizeService(registry.getOrThrow(PROGRAM), 'References'); + const refCount = types.find((t) => t.name === 'ReferenceCount')!; + expect(refCount).toBeDefined(); + // ReferenceCount(u32) is a tuple struct, parser may report as struct or alias + expect(refCount.kind).toMatch(/struct|alias/); + }); + + test('throws on unknown service', () => { + expect(() => + summarizeService(registry.getOrThrow(PROGRAM), 'NoSuchService'), + ).toThrow(/NoSuchService/); + }); +}); + +// --------------------------------------------------------------------------- +// summarizeFunction +// --------------------------------------------------------------------------- + +describe('summarizeFunction', () => { + test('returns function detail with service and interface_id', () => { + const detail = summarizeFunction(registry.getOrThrow(PROGRAM), 'Counter', 'Add'); + expect(detail.name).toBe('Add'); + expect(detail.service).toBe('Counter'); + expect(detail.interface_id).toBe('0x579d6daba41b7d82'); + }); + + test('entry_id is sequential index', () => { + const add = summarizeFunction(registry.getOrThrow(PROGRAM), 'Counter', 'Add'); + const sub = summarizeFunction(registry.getOrThrow(PROGRAM), 'Counter', 'Sub'); + expect(typeof add.entry_id).toBe('number'); + expect(sub.entry_id).toBe(add.entry_id + 1); + }); + + test('params and return_type resolved by TypeResolver', () => { + const detail = summarizeFunction(registry.getOrThrow(PROGRAM), 'Counter', 'Add'); + expect(detail.params).toEqual([{ name: 'value', type: 'u32' }]); + expect(detail.return_type).toBe('u32'); + }); + + test('multi-param function', () => { + const detail = summarizeFunction(registry.getOrThrow(PROGRAM), 'ThisThat', 'DoThis'); + expect(detail.params[0]).toEqual({ name: 'p1', type: 'u32' }); + expect(detail.params[1]).toEqual({ name: 'p2', type: 'String' }); + }); + + test('throws on unknown function', () => { + expect(() => + summarizeFunction(registry.getOrThrow(PROGRAM), 'Counter', 'NoSuchFunc'), + ).toThrow(/NoSuchFunc/); + }); + + test('throws on unknown service', () => { + expect(() => + summarizeFunction(registry.getOrThrow(PROGRAM), 'NoSuchService', 'Add'), + ).toThrow(/NoSuchService/); + }); +}); diff --git a/js/parser-idl-v2/src/idl-v2-impls.ts b/js/parser-idl-v2/src/idl-v2-impls.ts index 6a4534875..bc8fc0573 100644 --- a/js/parser-idl-v2/src/idl-v2-impls.ts +++ b/js/parser-idl-v2/src/idl-v2-impls.ts @@ -84,12 +84,14 @@ class ServiceExpo extends ServiceIdent implements IServiceExpo { class CtorFunc implements ICtorFunc { public readonly name: string; public readonly params?: FuncParam[]; + public readonly throws?: TypeDecl; public readonly docs?: string[]; public readonly annotations?: AnnotationEntry[]; constructor(data: ICtorFunc) { this.name = data.name; this.params = mapArray(data.params, (param) => new FuncParam(param)); + this.throws = data.throws; this.docs = data.docs; this.annotations = data.annotations; } diff --git a/js/src/sails-idl-v2.ts b/js/src/sails-idl-v2.ts index ca7477a9d..ed13076a4 100644 --- a/js/src/sails-idl-v2.ts +++ b/js/src/sails-idl-v2.ts @@ -364,6 +364,11 @@ export class SailsService implements ISailsService { return this._typeResolver.registry; } + /** #### TypeResolver with registered types from the ServiceUnit */ + get typeResolver() { + return this._typeResolver; + } + private _getFunctions(service: IServiceUnit): { funcs: Record; queries: Record; diff --git a/js/types/src/idl-v2-types.ts b/js/types/src/idl-v2-types.ts index 58f2c4d98..17c5ce162 100644 --- a/js/types/src/idl-v2-types.ts +++ b/js/types/src/idl-v2-types.ts @@ -36,6 +36,7 @@ export interface IServiceExpo extends IServiceIdent, IDocAnnotated { export interface ICtorFunc extends IDocAnnotated { name: string; params?: IFuncParam[]; + throws?: TypeDecl; } export interface IServiceUnit extends IServiceIdent, IDocAnnotated { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3699c835b..c8a070032 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -166,7 +166,7 @@ importers: devDependencies: '@gear-js/api': specifier: 0.44.2 - version: 0.44.2(@polkadot/api@16.4.6)(@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))))(rxjs@7.8.2) + version: 0.44.2(@polkadot/api@16.4.6)(@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6))))(rxjs@7.8.2) '@polkadot/api': specifier: 16.4.6 version: 16.4.6 @@ -183,8 +183,8 @@ importers: js/mcp-server: dependencies: '@modelcontextprotocol/sdk': - specifier: ^1.12.1 - version: 1.29.0(zod@3.25.76) + specifier: ^1.29.0 + version: 1.29.0(zod@4.3.6) sails-js: specifier: workspace:* version: link:.. @@ -197,9 +197,12 @@ importers: sails-js-util: specifier: workspace:* version: link:../util + viem: + specifier: ^2.0.0 + version: 2.47.6(typescript@5.9.3)(zod@4.3.6) zod: - specifier: ^3.24.0 - version: 3.25.76 + specifier: ^4.0.0 + version: 4.3.6 js/parser: optionalDependencies: @@ -223,6 +226,9 @@ importers: packages: + '@adraffy/ens-normalize@1.11.1': + resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -728,6 +734,14 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.1': + resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} + engines: {node: ^14.21.3 || >=16} + '@noble/curves@1.9.7': resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} engines: {node: ^14.21.3 || >=16} @@ -1125,6 +1139,12 @@ packages: '@scure/base@1.2.6': resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} + '@scure/bip32@1.7.0': + resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} + + '@scure/bip39@1.6.0': + resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + '@sinclair/typebox@0.34.48': resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} @@ -1380,6 +1400,17 @@ packages: cpu: [x64] os: [win32] + abitype@1.2.3: + resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -1805,6 +1836,9 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -2116,6 +2150,11 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isows@1.0.7: + resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} + peerDependencies: + ws: '*' + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -2491,6 +2530,14 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ox@0.14.7: + resolution: {integrity: sha512-zSQ/cfBdolj7U4++NAvH7sI+VG0T3pEohITCgcQj8KlawvTDY4vGVhDT64Atsm0d6adWfIYHDpu88iUBMMp+AQ==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -2959,6 +3006,14 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + viem@2.47.6: + resolution: {integrity: sha512-zExmbI99NGvMdYa7fmqSTLgkwh48dmhgEqFrUgkpL4kfG4XkVefZ8dZqIKVUhZo6Uhf0FrrEXOsHm9LUyIvI2Q==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -2997,6 +3052,18 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -3041,11 +3108,13 @@ packages: peerDependencies: zod: ^3.25.28 || ^4 - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: + '@adraffy/ens-normalize@1.11.1': {} + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -3307,12 +3376,6 @@ snapshots: '@polkadot/wasm-crypto': 7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6))) rxjs: 7.8.2 - '@gear-js/api@0.44.2(@polkadot/api@16.4.6)(@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))))(rxjs@7.8.2)': - dependencies: - '@polkadot/api': 16.4.6 - '@polkadot/wasm-crypto': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) - rxjs: 7.8.2 - '@hono/node-server@1.19.12(hono@4.12.9)': dependencies: hono: 4.12.9 @@ -3675,7 +3738,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.29.0(zod@4.3.6)': dependencies: '@hono/node-server': 1.19.12(hono@4.12.9) ajv: 8.18.0 @@ -3692,8 +3755,8 @@ snapshots: json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.2(zod@3.25.76) + zod: 4.3.6 + zod-to-json-schema: 3.25.2(zod@4.3.6) transitivePeerDependencies: - supports-color @@ -3704,6 +3767,12 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.9.1': + dependencies: + '@noble/hashes': 1.8.0 + '@noble/curves@1.9.7': dependencies: '@noble/hashes': 1.8.0 @@ -3962,23 +4031,11 @@ snapshots: '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)) tslib: 2.8.1 - '@polkadot/wasm-bridge@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)))': - dependencies: - '@polkadot/util': 13.5.9 - '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)) - tslib: 2.8.1 - '@polkadot/wasm-crypto-asmjs@7.5.4(@polkadot/util@13.5.6)': dependencies: '@polkadot/util': 13.5.6 tslib: 2.8.1 - '@polkadot/wasm-crypto-asmjs@7.5.4(@polkadot/util@13.5.9)': - dependencies: - '@polkadot/util': 13.5.9 - tslib: 2.8.1 - '@polkadot/wasm-crypto-init@7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)))': dependencies: '@polkadot/util': 13.5.6 @@ -3989,28 +4046,12 @@ snapshots: '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)) tslib: 2.8.1 - '@polkadot/wasm-crypto-init@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)))': - dependencies: - '@polkadot/util': 13.5.9 - '@polkadot/wasm-bridge': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) - '@polkadot/wasm-crypto-asmjs': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/wasm-crypto-wasm': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)) - tslib: 2.8.1 - '@polkadot/wasm-crypto-wasm@7.5.4(@polkadot/util@13.5.6)': dependencies: '@polkadot/util': 13.5.6 '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.6) tslib: 2.8.1 - '@polkadot/wasm-crypto-wasm@7.5.4(@polkadot/util@13.5.9)': - dependencies: - '@polkadot/util': 13.5.9 - '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) - tslib: 2.8.1 - '@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.6)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)))': dependencies: '@polkadot/util': 13.5.6 @@ -4022,27 +4063,11 @@ snapshots: '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.6)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)) tslib: 2.8.1 - '@polkadot/wasm-crypto@7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)))': - dependencies: - '@polkadot/util': 13.5.9 - '@polkadot/wasm-bridge': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) - '@polkadot/wasm-crypto-asmjs': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/wasm-crypto-init': 7.5.4(@polkadot/util@13.5.9)(@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))) - '@polkadot/wasm-crypto-wasm': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/x-randomvalues': 13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)) - tslib: 2.8.1 - '@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.6)': dependencies: '@polkadot/util': 13.5.6 tslib: 2.8.1 - '@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9)': - dependencies: - '@polkadot/util': 13.5.9 - tslib: 2.8.1 - '@polkadot/x-bigint@13.5.6': dependencies: '@polkadot/x-global': 13.5.6 @@ -4074,13 +4099,6 @@ snapshots: '@polkadot/x-global': 13.5.9 tslib: 2.8.1 - '@polkadot/x-randomvalues@13.5.9(@polkadot/util@13.5.9)(@polkadot/wasm-util@7.5.4(@polkadot/util@13.5.9))': - dependencies: - '@polkadot/util': 13.5.9 - '@polkadot/wasm-util': 7.5.4(@polkadot/util@13.5.9) - '@polkadot/x-global': 13.5.9 - tslib: 2.8.1 - '@polkadot/x-textdecoder@13.5.6': dependencies: '@polkadot/x-global': 13.5.6 @@ -4237,6 +4255,17 @@ snapshots: '@scure/base@1.2.6': {} + '@scure/bip32@1.7.0': + dependencies: + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@scure/bip39@1.6.0': + dependencies: + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@sinclair/typebox@0.34.48': {} '@sinonjs/commons@3.0.1': @@ -4501,6 +4530,11 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + abitype@1.2.3(typescript@5.9.3)(zod@4.3.6): + optionalDependencies: + typescript: 5.9.3 + zod: 4.3.6 + accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -4916,6 +4950,8 @@ snapshots: etag@1.8.1: {} + eventemitter3@5.0.1: {} + eventemitter3@5.0.4: {} eventsource-parser@3.0.6: {} @@ -5242,6 +5278,10 @@ snapshots: isexe@2.0.0: {} + isows@1.0.7(ws@8.18.3): + dependencies: + ws: 8.18.3 + istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@6.0.3: @@ -5779,6 +5819,21 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ox@0.14.7(typescript@5.9.3)(zod@4.3.6): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.3.6) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -6263,6 +6318,23 @@ snapshots: vary@1.1.2: {} + viem@2.47.6(typescript@5.9.3)(zod@4.3.6): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.3.6) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.7(typescript@5.9.3)(zod@4.3.6) + ws: 8.18.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -6302,6 +6374,8 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@8.18.3: {} + ws@8.19.0: {} y18n@5.0.8: {} @@ -6326,8 +6400,8 @@ snapshots: yoctocolors-cjs@2.1.3: {} - zod-to-json-schema@3.25.2(zod@3.25.76): + zod-to-json-schema@3.25.2(zod@4.3.6): dependencies: - zod: 3.25.76 + zod: 4.3.6 - zod@3.25.76: {} + zod@4.3.6: {} From 438b61b899e9f22cee51da3075d455939c3d936c Mon Sep 17 00:00:00 2001 From: vobradovich Date: Wed, 1 Apr 2026 12:11:00 +0200 Subject: [PATCH 3/5] cleanup --- js/mcp-server/src/tools/abi-tools.ts | 4 ++-- js/mcp-server/src/tools/util-tools.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/js/mcp-server/src/tools/abi-tools.ts b/js/mcp-server/src/tools/abi-tools.ts index 6a2b21fda..f3d6e4ef8 100644 --- a/js/mcp-server/src/tools/abi-tools.ts +++ b/js/mcp-server/src/tools/abi-tools.ts @@ -53,7 +53,7 @@ export function typeDeclToSolidity(td: TypeDecl): string { if (td.kind === 'named') { throw new Error( `Named type "${td.name}" is not supported in Sails ABI encoding. ` + - 'Only primitives, slices, and fixed arrays are allowed.', + 'Only primitives, slices, and fixed arrays are allowed.', ); } throw new Error(`Unknown TypeDecl: ${JSON.stringify(td)}`); @@ -567,7 +567,7 @@ export function registerAbiTools(server: McpServer) { service: z.string().describe('Service name'), event: z.string().describe('Event name'), fields: z - .record(z.any()) + .record(z.string(), z.any()) .describe('Event field values as a JSON object { fieldName: value }'), }, annotations: { readOnlyHint: true }, diff --git a/js/mcp-server/src/tools/util-tools.ts b/js/mcp-server/src/tools/util-tools.ts index f5b0730dd..050af5fb8 100644 --- a/js/mcp-server/src/tools/util-tools.ts +++ b/js/mcp-server/src/tools/util-tools.ts @@ -170,7 +170,6 @@ export function registerUtilTools(server: McpServer) { }; } - const targetIidU64 = header.interfaceId.asU64(); const targetEntryId = header.entryId; // Search all services for a match From e2e40c8f64ec4655bae51315c80631086eec4796 Mon Sep 17 00:00:00 2001 From: vobradovich Date: Wed, 1 Apr 2026 14:39:11 +0200 Subject: [PATCH 4/5] fix: bugs, lint --- js/mcp-server/src/idl-loader.ts | 16 +- js/mcp-server/src/index.ts | 8 +- js/mcp-server/src/registry.ts | 4 +- js/mcp-server/src/resources.ts | 10 +- js/mcp-server/src/tools/abi-tools.ts | 171 +++++++++-------- js/mcp-server/src/tools/codec-tools.ts | 20 +- js/mcp-server/src/tools/header-tools.ts | 24 +-- js/mcp-server/src/tools/idl-tools.ts | 16 +- js/mcp-server/src/tools/source-tools.ts | 8 +- js/mcp-server/src/tools/type-tools.ts | 23 +-- js/mcp-server/src/tools/util-tools.ts | 18 +- js/mcp-server/src/wasm-extractor.ts | 4 +- js/mcp-server/tests/abi-tools.test.ts | 60 +++++- js/mcp-server/tests/codec-tools.test.ts | 37 ++++ js/mcp-server/tests/tool-routing.test.ts | 94 +++++++++ js/mcp-server/tests/type-tools.test.ts | 231 +++++++++++++++++++++++ js/parser-idl-v2/src/index.ts | 2 +- js/src/sails-idl-v2.ts | 38 +++- 18 files changed, 623 insertions(+), 161 deletions(-) create mode 100644 js/mcp-server/tests/tool-routing.test.ts create mode 100644 js/mcp-server/tests/type-tools.test.ts diff --git a/js/mcp-server/src/idl-loader.ts b/js/mcp-server/src/idl-loader.ts index 642c7b9a4..e23a17062 100644 --- a/js/mcp-server/src/idl-loader.ts +++ b/js/mcp-server/src/idl-loader.ts @@ -1,5 +1,5 @@ import { readFile } from 'node:fs/promises'; -import { resolve, dirname } from 'node:path'; +import path from 'node:path'; interface IdlSource { content: string; @@ -16,16 +16,16 @@ interface IdlLoader { * Resolves relative include paths against the directory of the including file. */ class FsLoader implements IdlLoader { - async load(path: string): Promise { - const canonical = resolve(path); - const content = await readFile(canonical, 'utf-8'); + async load(filePath: string): Promise { + const canonical = path.resolve(filePath); + const content = await readFile(canonical, 'utf8'); return { content, id: canonical }; } resolve(basePath: string, includePath: string): string | null { if (includePath.startsWith('git://')) return null; - const baseDir = dirname(resolve(basePath)); - return resolve(baseDir, includePath); + const baseDir = path.dirname(path.resolve(basePath)); + return path.resolve(baseDir, includePath); } } @@ -119,7 +119,7 @@ async function preprocessRecursive( if (trimmed.startsWith('!@include:')) { const rest = trimmed.slice('!@include:'.length).trim(); - const includePath = rest.replace(/^["']|["']$/g, ''); + const includePath = rest.replaceAll(/^["']|["']$/g, ''); if (!includePath) { throw new Error('Invalid include directive'); @@ -139,7 +139,7 @@ async function preprocessRecursive( await preprocessRecursive(nextPath, loaders, visited, out); // Ensure newline after included content - if (out.length > 0 && !out[out.length - 1].endsWith('\n')) { + if (out.length > 0 && !out.at(-1).endsWith('\n')) { out.push('\n'); } } else { diff --git a/js/mcp-server/src/index.ts b/js/mcp-server/src/index.ts index 22be024c3..cf60d7de1 100644 --- a/js/mcp-server/src/index.ts +++ b/js/mcp-server/src/index.ts @@ -36,9 +36,11 @@ registerAbiTools(server); registerResources(server); // Initialize the WASM parser eagerly so first tool call is fast -getParser().catch((err) => { - console.error('Warning: Failed to pre-initialize IDL parser:', err.message); -}); +try { + await getParser(); +} catch (error: any) { + console.error('Warning: Failed to pre-initialize IDL parser:', error.message); +} // Start the stdio transport const transport = new StdioServerTransport(); diff --git a/js/mcp-server/src/registry.ts b/js/mcp-server/src/registry.ts index 1ced3c60c..a6022c753 100644 --- a/js/mcp-server/src/registry.ts +++ b/js/mcp-server/src/registry.ts @@ -1,4 +1,4 @@ -import { SailsProgram, SailsService } from 'sails-js'; +import { SailsProgram } from 'sails-js'; import type { IIdlDoc } from 'sails-js-types'; export interface RegisteredProgram { @@ -37,7 +37,7 @@ class ProgramRegistry { } list(): RegisteredProgram[] { - return Array.from(this.programs.values()); + return [...this.programs.values()]; } has(name: string): boolean { diff --git a/js/mcp-server/src/resources.ts b/js/mcp-server/src/resources.ts index eb49a888f..d26c956ee 100644 --- a/js/mcp-server/src/resources.ts +++ b/js/mcp-server/src/resources.ts @@ -1,17 +1,17 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { readFile } from 'node:fs/promises'; -import { resolve, dirname } from 'node:path'; +import path from 'node:path'; import { fileURLToPath } from 'node:url'; // Resolve paths relative to the repo root (js/mcp-server -> repo root) function repoRoot(): string { - const thisDir = dirname(fileURLToPath(import.meta.url)); - return resolve(thisDir, '..', '..', '..'); + const thisDir = path.dirname(fileURLToPath(import.meta.url)); + return path.resolve(thisDir, '..', '..', '..'); } async function readRepoFile(relativePath: string): Promise { - const fullPath = resolve(repoRoot(), relativePath); - return readFile(fullPath, 'utf-8'); + const fullPath = path.resolve(repoRoot(), relativePath); + return readFile(fullPath, 'utf8'); } export function registerResources(server: McpServer) { diff --git a/js/mcp-server/src/tools/abi-tools.ts b/js/mcp-server/src/tools/abi-tools.ts index f3d6e4ef8..b810c684e 100644 --- a/js/mcp-server/src/tools/abi-tools.ts +++ b/js/mcp-server/src/tools/abi-tools.ts @@ -18,27 +18,65 @@ import type { TypeDecl, IIdlDoc, IServiceUnit, IServiceFunc, IStructField } from export function typeDeclToSolidity(td: TypeDecl): string { if (typeof td === 'string') { switch (td) { - case 'bool': return 'bool'; - case 'u8': return 'uint8'; - case 'u16': return 'uint16'; - case 'u32': return 'uint32'; - case 'u64': return 'uint64'; - case 'u128': return 'uint128'; - case 'U256': return 'uint256'; - case 'i8': return 'int8'; - case 'i16': return 'int16'; - case 'i32': return 'int32'; - case 'i64': return 'int64'; - case 'i128': return 'int128'; - case 'String': return 'string'; - case 'ActorId': return 'address'; + case 'bool': { + return 'bool'; + } + case 'u8': { + return 'uint8'; + } + case 'u16': { + return 'uint16'; + } + case 'u32': { + return 'uint32'; + } + case 'u64': { + return 'uint64'; + } + case 'u128': { + return 'uint128'; + } + case 'U256': { + return 'uint256'; + } + case 'i8': { + return 'int8'; + } + case 'i16': { + return 'int16'; + } + case 'i32': { + return 'int32'; + } + case 'i64': { + return 'int64'; + } + case 'i128': { + return 'int128'; + } + case 'String': { + return 'string'; + } + case 'ActorId': { + return 'address'; + } case 'H256': case 'CodeId': - case 'MessageId': return 'bytes32'; - case 'H160': return 'bytes20'; - case '()': throw new Error('Void type () has no Solidity representation'); - case 'char': throw new Error('char type is not supported in Solidity ABI'); - default: throw new Error(`Unsupported primitive type in ABI: ${td}`); + case 'MessageId': { + return 'bytes32'; + } + case 'H160': { + return 'bytes20'; + } + case '()': { + throw new Error('Void type () has no Solidity representation'); + } + case 'char': { + throw new Error('char type is not supported in Solidity ABI'); + } + default: { + throw new Error(`Unsupported primitive type in ABI: ${td}`); + } } } if (td.kind === 'slice') { @@ -128,14 +166,10 @@ function isIndexed(field: IStructField): boolean { function generateSolidity(doc: IIdlDoc, baseName: string): string { const services = doc.services ?? []; - const lines: string[] = []; + const lines: string[] = ['// SPDX-License-Identifier: UNLICENSED', 'pragma solidity ^0.8.26;', '', `interface I${baseName} {`]; - lines.push('// SPDX-License-Identifier: UNLICENSED'); - lines.push('pragma solidity ^0.8.26;'); - lines.push(''); // Contract 1: Interface - lines.push(`interface I${baseName} {`); for (const unit of services) { for (const func of unit.funcs ?? []) { const solName = solFuncName(unit.name, func.name); @@ -169,11 +203,7 @@ function generateSolidity(doc: IIdlDoc, baseName: string): string { lines.push(` event ${event.name}(${fieldList});`); } } - lines.push('}'); - lines.push(''); - - // Contract 2: Abi (pure selector functions) - lines.push(`abstract contract ${baseName}Abi {`); + lines.push('}', '', `abstract contract ${baseName}Abi {`); for (const unit of services) { for (const func of unit.funcs ?? []) { const solName = solFuncName(unit.name, func.name); @@ -182,16 +212,10 @@ function generateSolidity(doc: IIdlDoc, baseName: string): string { ...(func.params ?? []).map((p) => typeDeclToSolidity(p.type)), ]; const sig = buildSignature(solName, paramTypes); - lines.push(` function ${solName}_sig() public pure returns (bytes4) {`); - lines.push(` return bytes4(keccak256("${sig}"));`); - lines.push(` }`); + lines.push(` function ${solName}_sig() public pure returns (bytes4) {`, ` return bytes4(keccak256("${sig}"));`, ` }`); } } - lines.push('}'); - lines.push(''); - - // Contract 3: Callbacks interface - lines.push(`interface I${baseName}Callbacks {`); + lines.push('}', '', `interface I${baseName}Callbacks {`); for (const unit of services) { for (const func of unit.funcs ?? []) { if (func.output && func.output !== '()') { @@ -201,14 +225,7 @@ function generateSolidity(doc: IIdlDoc, baseName: string): string { } } } - lines.push('}'); - lines.push(''); - - // Contract 4: Caller (abstract helper) - lines.push(`abstract contract ${baseName}Caller {`); - lines.push(` address public immutable program;`); - lines.push(` constructor(address _program) { program = _program; }`); - lines.push(''); + lines.push('}', '', `abstract contract ${baseName}Caller {`, ` address public immutable program;`, ` constructor(address _program) { program = _program; }`, ''); for (const unit of services) { for (const func of unit.funcs ?? []) { const solName = solFuncName(unit.name, func.name); @@ -219,10 +236,8 @@ function generateSolidity(doc: IIdlDoc, baseName: string): string { const passArgs = (func.params ?? []).map((p) => p.name).join(', '); const callArgs = passArgs ? `false, ${passArgs}` : 'false'; lines.push( - ` function ${solName}(${paramList}) internal${payableKw} returns (bytes32 messageId) {`, - ); - lines.push(` return I${baseName}(program).${solName}(${callArgs});`); - lines.push(` }`); + ` function ${solName}(${paramList}) internal${payableKw} returns (bytes32 messageId) {`, ` return I${baseName}(program).${solName}(${callArgs});` + , ` }`); } } lines.push('}'); @@ -267,8 +282,8 @@ export function registerAbiTools(server: McpServer) { }, ], }; - } catch (err: any) { - return { isError: true, content: [{ type: 'text', text: err.message }] }; + } catch (error: any) { + return { isError: true, content: [{ type: 'text', text: error.message }] }; } }, ); @@ -277,7 +292,7 @@ export function registerAbiTools(server: McpServer) { 'sails_solidity_signature', { description: - 'Compute the Solidity function/event signature and 4-byte selector for an IDL function or event. ' + + 'Compute the Solidity function signature + 4-byte selector, or the event signature + full topic hash. ' + 'Functions include the implicit bool _callReply first param. ' + 'Function names follow ethexe convention: camelCase(ServiceName + FunctionName).', inputSchema: { @@ -327,18 +342,18 @@ export function registerAbiTools(server: McpServer) { } const fieldTypes = (event.fields ?? []).map((f) => typeDeclToSolidity(f.type)); const sig = buildSignature(targetName, fieldTypes); - const sel = computeSelector(sig); + const topic = keccak256(toHex(sig)); return { content: [ { type: 'text', - text: JSON.stringify({ signature: sig, selector: sel }, null, 2), + text: JSON.stringify({ signature: sig, topic }, null, 2), }, ], }; } - } catch (err: any) { - return { isError: true, content: [{ type: 'text', text: err.message }] }; + } catch (error: any) { + return { isError: true, content: [{ type: 'text', text: error.message }] }; } }, ); @@ -405,10 +420,10 @@ export function registerAbiTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `ABI encode error: ${err.message}` }], + content: [{ type: 'text', text: `ABI encode error: ${error.message}` }], }; } }, @@ -457,9 +472,9 @@ export function registerAbiTools(server: McpServer) { ); const [callReply, ...funcArgs] = decoded; const argsObj: Record = {}; - (func.params ?? []).forEach((p, i) => { + for (const [i, p] of (func.params ?? []).entries()) { argsObj[p.name] = funcArgs[i]; - }); + } return { content: [ @@ -485,10 +500,10 @@ export function registerAbiTools(server: McpServer) { throw new Error( `No function matches selector ${callSelector} in program "${programName}"`, ); - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `ABI decode error: ${err.message}` }], + content: [{ type: 'text', text: `ABI decode error: ${error.message}` }], }; } }, @@ -546,10 +561,10 @@ export function registerAbiTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `ABI decode error: ${err.message}` }], + content: [{ type: 'text', text: `ABI decode error: ${error.message}` }], }; } }, @@ -582,8 +597,8 @@ export function registerAbiTools(server: McpServer) { } const allFields = event.fields ?? []; - const indexedFields = allFields.filter(isIndexed); - const dataFields = allFields.filter((f) => !isIndexed(f)); + const indexedFields = allFields.filter((field) => isIndexed(field)); + const dataFields = allFields.filter((field) => !isIndexed(field)); // Event signature hash → topic[0] const fieldTypes = allFields.map((f) => typeDeclToSolidity(f.type)); @@ -618,10 +633,10 @@ export function registerAbiTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `ABI event encode error: ${err.message}` }], + content: [{ type: 'text', text: `ABI event encode error: ${error.message}` }], }; } }, @@ -675,12 +690,12 @@ export function registerAbiTools(server: McpServer) { } const allFields = targetEvent.fields ?? []; - const indexedFields = allFields.filter(isIndexed); - const dataFields = allFields.filter((f) => !isIndexed(f)); + const indexedFields = allFields.filter((field) => isIndexed(field)); + const dataFields = allFields.filter((field) => !isIndexed(field)); const result: Record = {}; // Decode indexed fields from topics[1..] - indexedFields.forEach((field, i) => { + for (const [i, field] of indexedFields.entries()) { const topic = topics[i + 1]; if (topic) { const solType = typeDeclToSolidity(field.type); @@ -693,7 +708,7 @@ export function registerAbiTools(server: McpServer) { ); result[field.name ?? `indexed_${i}`] = decoded[0]; } - }); + } // Decode non-indexed from data if (dataFields.length > 0 && data && data !== '0x') { @@ -701,9 +716,9 @@ export function registerAbiTools(server: McpServer) { toAbiParam(f.name ?? '', f.type), ); const decoded = decodeAbiParameters(dataParams, data as `0x${string}`); - dataFields.forEach((f, i) => { + for (const [i, f] of dataFields.entries()) { result[f.name ?? `data_${i}`] = decoded[i]; - }); + } } return { @@ -714,10 +729,10 @@ export function registerAbiTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `ABI event decode error: ${err.message}` }], + content: [{ type: 'text', text: `ABI event decode error: ${error.message}` }], }; } }, @@ -749,10 +764,10 @@ export function registerAbiTools(server: McpServer) { return { content: [{ type: 'text', text: solidity }], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Solidity generation error: ${err.message}` }], + content: [{ type: 'text', text: `Solidity generation error: ${error.message}` }], }; } }, diff --git a/js/mcp-server/src/tools/codec-tools.ts b/js/mcp-server/src/tools/codec-tools.ts index d933da9b1..be34d60fe 100644 --- a/js/mcp-server/src/tools/codec-tools.ts +++ b/js/mcp-server/src/tools/codec-tools.ts @@ -71,10 +71,10 @@ export function registerCodecTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Encode error: ${err.message}` }], + content: [{ type: 'text', text: `Encode error: ${error.message}` }], }; } }, @@ -107,10 +107,10 @@ export function registerCodecTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Decode error: ${err.message}` }], + content: [{ type: 'text', text: `Decode error: ${error.message}` }], }; } }, @@ -142,10 +142,10 @@ export function registerCodecTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Decode error: ${err.message}` }], + content: [{ type: 'text', text: `Decode error: ${error.message}` }], }; } }, @@ -181,10 +181,10 @@ export function registerCodecTools(server: McpServer) { return { content: [{ type: 'text', text: JSON.stringify({ hex }, null, 2) }], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Encode error: ${err.message}` }], + content: [{ type: 'text', text: `Encode error: ${error.message}` }], }; } }, @@ -252,10 +252,10 @@ export function registerCodecTools(server: McpServer) { throw new Error( `Could not match event in service "${serviceName}". No event entry_id matched the payload header.`, ); - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Event decode error: ${err.message}` }], + content: [{ type: 'text', text: `Event decode error: ${error.message}` }], }; } }, diff --git a/js/mcp-server/src/tools/header-tools.ts b/js/mcp-server/src/tools/header-tools.ts index a85437b5a..3996addd2 100644 --- a/js/mcp-server/src/tools/header-tools.ts +++ b/js/mcp-server/src/tools/header-tools.ts @@ -8,13 +8,13 @@ function hexToBytes(hex: string): Uint8Array { if (h.length % 2 !== 0) h = '0' + h; const bytes = new Uint8Array(h.length / 2); for (let i = 0; i < bytes.length; i++) { - bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16); + bytes[i] = Number.parseInt(h.slice(i * 2, i * 2 + 2), 16); } return bytes; } function bytesToHex(bytes: Uint8Array): string { - return '0x' + Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join(''); + return '0x' + [...bytes].map((b) => b.toString(16).padStart(2, '0')).join(''); } export function registerHeaderTools(server: McpServer) { @@ -59,10 +59,10 @@ export function registerHeaderTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Header parse error: ${err.message}` }], + content: [{ type: 'text', text: `Header parse error: ${error.message}` }], }; } }, @@ -78,7 +78,7 @@ export function registerHeaderTools(server: McpServer) { interface_id: z .string() .describe('Interface ID as hex string (e.g. "0x579d6daba41b7d82")'), - entry_id: z.number().int().min(0).max(65535).describe('Entry ID (u16, 0-65535)'), + entry_id: z.number().int().min(0).max(65_535).describe('Entry ID (u16, 0-65535)'), route_idx: z.number().int().min(0).max(255).default(0).describe('Route index (u8, 0-255)'), }, annotations: { readOnlyHint: true }, @@ -96,7 +96,7 @@ export function registerHeaderTools(server: McpServer) { text: JSON.stringify( { hex: bytesToHex(bytes), - bytes: Array.from(bytes), + bytes: [...bytes], }, null, 2, @@ -104,10 +104,10 @@ export function registerHeaderTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Header build error: ${err.message}` }], + content: [{ type: 'text', text: `Header build error: ${error.message}` }], }; } }, @@ -159,10 +159,10 @@ export function registerHeaderTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: err.message }], + content: [{ type: 'text', text: error.message }], }; } }, @@ -204,10 +204,10 @@ export function registerHeaderTools(server: McpServer) { return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: err.message }], + content: [{ type: 'text', text: error.message }], }; } }, diff --git a/js/mcp-server/src/tools/idl-tools.ts b/js/mcp-server/src/tools/idl-tools.ts index a1dfe9a3b..03a845aff 100644 --- a/js/mcp-server/src/tools/idl-tools.ts +++ b/js/mcp-server/src/tools/idl-tools.ts @@ -43,10 +43,10 @@ export function registerIdlTools(server: McpServer) { return { content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `IDL parse error: ${err.message}` }], + content: [{ type: 'text', text: `IDL parse error: ${error.message}` }], }; } }, @@ -70,13 +70,13 @@ export function registerIdlTools(server: McpServer) { return { content: [{ type: 'text', text: JSON.stringify({ valid: true, errors: null }, null, 2) }], }; - } catch (err: any) { + } catch (error: any) { return { content: [ { type: 'text', text: JSON.stringify( - { valid: false, errors: [err.message] }, + { valid: false, errors: [error.message] }, null, 2, ), @@ -106,10 +106,10 @@ export function registerIdlTools(server: McpServer) { return { content: [{ type: 'text', text: JSON.stringify(detail, null, 2) }], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: err.message }], + content: [{ type: 'text', text: error.message }], }; } }, @@ -136,10 +136,10 @@ export function registerIdlTools(server: McpServer) { return { content: [{ type: 'text', text: JSON.stringify(detail, null, 2) }], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: err.message }], + content: [{ type: 'text', text: error.message }], }; } }, diff --git a/js/mcp-server/src/tools/source-tools.ts b/js/mcp-server/src/tools/source-tools.ts index 6f5813b24..1fae1dbe8 100644 --- a/js/mcp-server/src/tools/source-tools.ts +++ b/js/mcp-server/src/tools/source-tools.ts @@ -37,10 +37,10 @@ export function registerSourceTools(server: McpServer) { return { content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Load IDL error: ${err.message}` }], + content: [{ type: 'text', text: `Load IDL error: ${error.message}` }], }; } }, @@ -82,10 +82,10 @@ export function registerSourceTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `WASM extract error: ${err.message}` }], + content: [{ type: 'text', text: `WASM extract error: ${error.message}` }], }; } }, diff --git a/js/mcp-server/src/tools/type-tools.ts b/js/mcp-server/src/tools/type-tools.ts index 2a995d859..f4831c65b 100644 --- a/js/mcp-server/src/tools/type-tools.ts +++ b/js/mcp-server/src/tools/type-tools.ts @@ -45,19 +45,12 @@ export function registerTypeTools(server: McpServer) { for (const { scope, types } of searchScopes) { const found = types.find((t: any) => t.name === type_name); if (found) { + const { name, ...definition } = found; return { content: [ { type: 'text', - text: JSON.stringify( - { - name: found.name, - scope, - definition: found.def, - }, - null, - 2, - ), + text: JSON.stringify({ name, scope, definition }, null, 2), }, ], }; @@ -75,10 +68,10 @@ export function registerTypeTools(server: McpServer) { throw new Error( `Type "${type_name}" not found. Available types: [${allTypes.join(', ')}]`, ); - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: err.message }], + content: [{ type: 'text', text: error.message }], }; } }, @@ -116,10 +109,10 @@ export function registerTypeTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Encode type error: ${err.message}` }], + content: [{ type: 'text', text: `Encode type error: ${error.message}` }], }; } }, @@ -160,10 +153,10 @@ export function registerTypeTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Decode type error: ${err.message}` }], + content: [{ type: 'text', text: `Decode type error: ${error.message}` }], }; } }, diff --git a/js/mcp-server/src/tools/util-tools.ts b/js/mcp-server/src/tools/util-tools.ts index 050af5fb8..02608f8b5 100644 --- a/js/mcp-server/src/tools/util-tools.ts +++ b/js/mcp-server/src/tools/util-tools.ts @@ -1,16 +1,14 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; -import { SailsMessageHeader } from 'sails-js-parser-idl-v2'; +import { MAGIC_BYTES, SailsMessageHeader } from 'sails-js-parser-idl-v2'; import { registry } from '../registry.js'; -const SAILS_MAGIC = new Uint8Array([0x47, 0x4d]); // "GM" - function hexToBytes(hex: string): Uint8Array { let h = hex.startsWith('0x') ? hex.slice(2) : hex; if (h.length % 2 !== 0) h = '0' + h; const bytes = new Uint8Array(h.length / 2); for (let i = 0; i < bytes.length; i++) { - bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16); + bytes[i] = Number.parseInt(h.slice(i * 2, i * 2 + 2), 16); } return bytes; } @@ -84,7 +82,7 @@ export function registerUtilTools(server: McpServer) { } // Check for Sails magic bytes "GM" (0x47 0x4D) - if (bytes[0] === SAILS_MAGIC[0] && bytes[1] === SAILS_MAGIC[1]) { + if (bytes[0] === MAGIC_BYTES[0] && bytes[1] === MAGIC_BYTES[1]) { const details: any = { encoding: 'scale', magic: 'GM (0x474D)' }; if (bytes.length >= 16) { @@ -105,7 +103,7 @@ export function registerUtilTools(server: McpServer) { } // No Sails magic - likely ABI encoding (4-byte selector) - const selector = '0x' + Array.from(bytes.slice(0, 4)).map((b) => b.toString(16).padStart(2, '0')).join(''); + const selector = `0x${Array.from(bytes.subarray(0, 4), (byte) => byte.toString(16).padStart(2, '0')).join('')}`; return { content: [ { @@ -123,10 +121,10 @@ export function registerUtilTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Detection error: ${err.message}` }], + content: [{ type: 'text', text: `Detection error: ${error.message}` }], }; } }, @@ -252,10 +250,10 @@ export function registerUtilTools(server: McpServer) { }, ], }; - } catch (err: any) { + } catch (error: any) { return { isError: true, - content: [{ type: 'text', text: `Explain error: ${err.message}` }], + content: [{ type: 'text', text: `Explain error: ${error.message}` }], }; } }, diff --git a/js/mcp-server/src/wasm-extractor.ts b/js/mcp-server/src/wasm-extractor.ts index fb754ae51..756761dc1 100644 --- a/js/mcp-server/src/wasm-extractor.ts +++ b/js/mcp-server/src/wasm-extractor.ts @@ -42,7 +42,7 @@ async function parseWasmCustomSection( // WASM magic: \0asm if (wasm.length < 8) return null; - if (view.getUint32(0, true) !== 0x6d736100) return null; // \0asm in LE + if (view.getUint32(0, true) !== 0x6D_73_61_00) return null; // \0asm in LE offset = 4; // WASM version @@ -115,7 +115,7 @@ function readLeb128(bytes: Uint8Array, offset: number): { value: number; bytesRe while (offset + bytesRead < bytes.length) { const byte = bytes[offset + bytesRead]; - result |= (byte & 0x7f) << shift; + result |= (byte & 0x7F) << shift; bytesRead++; if ((byte & 0x80) === 0) break; shift += 7; diff --git a/js/mcp-server/tests/abi-tools.test.ts b/js/mcp-server/tests/abi-tools.test.ts index dd7af5b18..bbcd2f16f 100644 --- a/js/mcp-server/tests/abi-tools.test.ts +++ b/js/mcp-server/tests/abi-tools.test.ts @@ -1,7 +1,8 @@ import { describe, test, expect, beforeAll } from 'bun:test'; import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { registry } from '../src/registry'; -import { typeDeclToSolidity } from '../src/tools/abi-tools'; +import { registerAbiTools, typeDeclToSolidity } from '../src/tools/abi-tools'; import { encodeAbiParameters, decodeAbiParameters, @@ -17,12 +18,32 @@ const thisDir = dirname(fileURLToPath(import.meta.url)); const repoRoot = resolve(thisDir, '..', '..', '..'); const demoIdlPath = resolve(repoRoot, 'js/test/demo-v2/demo.idl'); +type ToolResult = { isError?: boolean; content: { type: string; text: string }[] }; + +function makeServer() { + const server = new McpServer({ name: 'test', version: '0.0.0' }); + registerAbiTools(server); + return server; +} + +async function callTool(server: McpServer, name: string, args: Record): Promise { + const result = await (server as any)._registeredTools[name].handler(args); + return result as ToolResult; +} + +function json(result: ToolResult) { + return JSON.parse(result.content[0].text); +} + +let server: McpServer; + beforeAll(async () => { const parser = new SailsIdlParser(); await parser.init(); const idl = await readFile(demoIdlPath, 'utf-8'); const doc = parser.parse(idl); registry.register('DemoClient', doc); + server = makeServer(); }); // --------------------------------------------------------------------------- @@ -161,6 +182,43 @@ describe('event topic computation', () => { }); }); +// --------------------------------------------------------------------------- +// Tool behavior +// --------------------------------------------------------------------------- + +describe('sails_solidity_signature tool', () => { + test('returns a 4-byte selector for functions', async () => { + const result = await callTool(server, 'sails_solidity_signature', { + program: 'DemoClient', + service: 'Counter', + name: 'Add', + kind: 'function', + }); + + expect(result.isError).toBeFalsy(); + expect(json(result)).toMatchObject({ + signature: 'counterAdd(bool,uint32)', + selector: keccak256(toHex('counterAdd(bool,uint32)')).slice(0, 10), + solidity_name: 'counterAdd', + }); + }); + + test('returns the full topic hash for events', async () => { + const result = await callTool(server, 'sails_solidity_signature', { + program: 'DemoClient', + service: 'Counter', + name: 'Added', + kind: 'event', + }); + + expect(result.isError).toBeFalsy(); + expect(json(result)).toEqual({ + signature: 'Added(uint32)', + topic: keccak256(toHex('Added(uint32)')), + }); + }); +}); + // --------------------------------------------------------------------------- // Solidity generation (smoke test via IDL doc inspection) // --------------------------------------------------------------------------- diff --git a/js/mcp-server/tests/codec-tools.test.ts b/js/mcp-server/tests/codec-tools.test.ts index 2e0a641a6..0c9c86f2c 100644 --- a/js/mcp-server/tests/codec-tools.test.ts +++ b/js/mcp-server/tests/codec-tools.test.ts @@ -1,5 +1,6 @@ import { describe, test, expect, beforeAll } from 'bun:test'; import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { SailsMessageHeader, InterfaceId } from 'sails-js-parser-idl-v2'; import { registry } from '../src/registry'; import { readFile } from 'node:fs/promises'; import { resolve, dirname } from 'node:path'; @@ -49,6 +50,17 @@ describe('SCALE codec encoding/decoding', () => { expect(decoded).toEqual({ value: 42 }); }); + test('decodePayload rejects payloads for a different function header', () => { + const entry = registry.getOrThrow('DemoClient'); + const counter = entry.program.services['Counter']; + const addFn = counter.functions['Add']; + const subFn = counter.functions['Sub']; + + const subPayload = subFn.encodePayload(42); + + expect(() => addFn.decodePayload(subPayload)).toThrow(/Header mismatch/); + }); + test('encode then decode result round-trip', () => { const entry = registry.getOrThrow('DemoClient'); const addFn = entry.program.services['Counter'].functions['Add']; @@ -109,4 +121,29 @@ describe('SCALE codec encoding/decoding', () => { // No args = just 16-byte header expect(hex.length).toBe(34); }); + + test('decodePayload returns empty args for a no-arg query payload', () => { + const entry = registry.getOrThrow('DemoClient'); + const valueFn = entry.program.services['Counter'].queries['Value']; + + const hex = valueFn.encodePayload(); + + expect(valueFn.decodePayload(hex)).toEqual({}); + }); + + test('event decode rejects payloads for a different event header', () => { + const entry = registry.getOrThrow('DemoClient'); + const counter = entry.program.services['Counter']; + const added = counter.events['Added']; + const subtracted = counter.events['Subtracted']; + const header = SailsMessageHeader.v1( + InterfaceId.fromString('0x579d6daba41b7d82'), + 1, + counter.routeIdx, + ); + const payload = counter.registry.createType('([u8; 16], u32)', [header.toBytes(), 7]).toHex(); + + expect(subtracted.decode(payload)).toBe(7); + expect(() => added.decode(payload)).toThrow(/Header mismatch/); + }); }); diff --git a/js/mcp-server/tests/tool-routing.test.ts b/js/mcp-server/tests/tool-routing.test.ts new file mode 100644 index 000000000..034c7d0e1 --- /dev/null +++ b/js/mcp-server/tests/tool-routing.test.ts @@ -0,0 +1,94 @@ +import { describe, test, expect, beforeAll } from 'bun:test'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { SailsIdlParser, SailsMessageHeader, InterfaceId } from 'sails-js-parser-idl-v2'; +import { registry } from '../src/registry'; +import { registerCodecTools } from '../src/tools/codec-tools'; +import { registerUtilTools } from '../src/tools/util-tools'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const thisDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(thisDir, '..', '..', '..'); +const demoIdlPath = resolve(repoRoot, 'js/test/demo-v2/demo.idl'); + +const PROGRAM = 'ToolRoutingDemo'; + +type ToolResult = { isError?: boolean; content: { type: string; text: string }[] }; + +function makeServer() { + const server = new McpServer({ name: 'test', version: '0.0.0' }); + registerCodecTools(server); + registerUtilTools(server); + return server; +} + +async function callTool(server: McpServer, name: string, args: Record): Promise { + const result = await (server as any)._registeredTools[name].handler(args); + return result as ToolResult; +} + +function json(result: ToolResult) { + return JSON.parse(result.content[0].text); +} + +let server: McpServer; + +beforeAll(async () => { + const parser = new SailsIdlParser(); + await parser.init(); + const idl = await readFile(demoIdlPath, 'utf-8'); + const doc = parser.parse(idl); + registry.register(PROGRAM, doc); + server = makeServer(); +}); + +describe('tool routing', () => { + test('sails_explain_payload identifies the matching function header', async () => { + const entry = registry.getOrThrow(PROGRAM); + const payload = entry.program.services['Counter'].functions['Sub'].encodePayload(42); + + const result = await callTool(server, 'sails_explain_payload', { + program: PROGRAM, + hex: payload, + }); + + expect(result.isError).toBeFalsy(); + expect(json(result)).toMatchObject({ + identified: true, + service: 'Counter', + function: 'Sub', + kind: 'command', + args: { value: 42 }, + }); + }); + + test('sails_decode_event auto-detects the matching event header', async () => { + const entry = registry.getOrThrow(PROGRAM); + const counter = entry.program.services['Counter']; + const header = SailsMessageHeader.v1( + InterfaceId.fromString('0x579d6daba41b7d82'), + 1, + counter.routeIdx, + ); + const payload = counter.registry + .createType('([u8; 16], u32)', [ + header.toBytes(), + 7, + ]) + .toHex(); + + const result = await callTool(server, 'sails_decode_event', { + program: PROGRAM, + service: 'Counter', + hex: payload, + }); + + expect(result.isError).toBeFalsy(); + expect(json(result)).toMatchObject({ + event: 'Subtracted', + data: 7, + auto_detected: true, + }); + }); +}); diff --git a/js/mcp-server/tests/type-tools.test.ts b/js/mcp-server/tests/type-tools.test.ts new file mode 100644 index 000000000..0c46c2bfd --- /dev/null +++ b/js/mcp-server/tests/type-tools.test.ts @@ -0,0 +1,231 @@ +import { describe, test, expect, beforeAll } from 'bun:test'; +import { SailsIdlParser } from 'sails-js-parser-idl-v2'; +import { registry } from '../src/registry'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { registerTypeTools } from '../src/tools/type-tools'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; + +const thisDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(thisDir, '..', '..', '..'); +const demoIdlPath = resolve(repoRoot, 'js/test/demo-v2/demo.idl'); + +const PROGRAM = 'TypeToolsDemo'; + +// Call a registered tool directly by invoking its handler via the server +type ToolResult = { isError?: boolean; content: { type: string; text: string }[] }; + +function makeServer() { + const server = new McpServer({ name: 'test', version: '0.0.0' }); + registerTypeTools(server); + return server; +} + +async function callTool(server: McpServer, name: string, args: Record): Promise { + const result = await (server as any)._registeredTools[name].handler(args); + return result as ToolResult; +} + +function json(result: ToolResult) { + return JSON.parse(result.content[0].text); +} + +let server: McpServer; + +beforeAll(async () => { + const parser = new SailsIdlParser(); + await parser.init(); + const idl = await readFile(demoIdlPath, 'utf-8'); + const doc = parser.parse(idl); + registry.register(PROGRAM, doc); + server = makeServer(); +}); + +// --------------------------------------------------------------------------- +// sails_resolve_type +// --------------------------------------------------------------------------- + +describe('sails_resolve_type', () => { + test('resolves a struct: name, scope, definition.kind, definition.fields', async () => { + const result = await callTool(server, 'sails_resolve_type', { + program: PROGRAM, + type_name: 'DoThatParam', + service: 'ThisThat', + }); + expect(result.isError).toBeFalsy(); + const { name, scope, definition } = json(result); + expect(name).toBe('DoThatParam'); + expect(scope).toBe('ThisThat'); + expect(definition.kind).toBe('struct'); + expect(Array.isArray(definition.fields)).toBe(true); + const fieldNames = definition.fields.map((f: any) => f.name); + expect(fieldNames).toEqual(expect.arrayContaining(['p1', 'p2', 'p3'])); + }); + + test('resolves an enum: definition.kind and definition.variants', async () => { + const result = await callTool(server, 'sails_resolve_type', { + program: PROGRAM, + type_name: 'ManyVariants', + service: 'ThisThat', + }); + expect(result.isError).toBeFalsy(); + const { name, scope, definition } = json(result); + expect(name).toBe('ManyVariants'); + expect(scope).toBe('ThisThat'); + expect(definition.kind).toBe('enum'); + expect(Array.isArray(definition.variants)).toBe(true); + const variantNames = definition.variants.map((v: any) => v.name); + expect(variantNames).toEqual(expect.arrayContaining(['One', 'Two', 'Three', 'Four', 'Five', 'Six'])); + }); + + test('auto-discovers type across all services; struct definition present', async () => { + const result = await callTool(server, 'sails_resolve_type', { + program: PROGRAM, + type_name: 'ReferenceCount', + }); + expect(result.isError).toBeFalsy(); + const { name, scope, definition } = json(result); + expect(name).toBe('ReferenceCount'); + expect(scope).toBe('References'); + // ReferenceCount(u32) is a tuple struct + expect(definition.kind).toBe('struct'); + expect(Array.isArray(definition.fields)).toBe(true); + }); + + test('returns error for unknown type', async () => { + const result = await callTool(server, 'sails_resolve_type', { + program: PROGRAM, + type_name: 'NoSuchType', + }); + expect(result.isError).toBe(true); + expect(result.content[0].text).toMatch(/NoSuchType/); + }); + + test('returns error for unknown program', async () => { + const result = await callTool(server, 'sails_resolve_type', { + program: 'NoSuchProgram', + type_name: 'DoThatParam', + }); + expect(result.isError).toBe(true); + expect(result.content[0].text).toMatch(/NoSuchProgram/); + }); +}); + +// --------------------------------------------------------------------------- +// sails_encode_type +// --------------------------------------------------------------------------- + +describe('sails_encode_type', () => { + test('encodes a u32 value', async () => { + const result = await callTool(server, 'sails_encode_type', { + program: PROGRAM, + service: 'Counter', + type_name: 'u32', + value: 42, + }); + expect(result.isError).toBeFalsy(); + const data = json(result); + expect(data.type).toBe('u32'); + expect(data.hex).toMatch(/^0x/); + }); + + test('encodes a bool value', async () => { + const result = await callTool(server, 'sails_encode_type', { + program: PROGRAM, + service: 'Counter', + type_name: 'bool', + value: true, + }); + expect(result.isError).toBeFalsy(); + expect(json(result).hex).toBe('0x01'); + }); + + test('returns error for unknown service', async () => { + const result = await callTool(server, 'sails_encode_type', { + program: PROGRAM, + service: 'NoSuchService', + type_name: 'u32', + value: 1, + }); + expect(result.isError).toBe(true); + expect(result.content[0].text).toMatch(/NoSuchService/); + }); + + test('returns error for unknown program', async () => { + const result = await callTool(server, 'sails_encode_type', { + program: 'NoSuchProgram', + service: 'Counter', + type_name: 'u32', + value: 1, + }); + expect(result.isError).toBe(true); + }); +}); + +// --------------------------------------------------------------------------- +// sails_decode_type +// --------------------------------------------------------------------------- + +describe('sails_decode_type', () => { + test('decodes a u32 value', async () => { + // First encode to get the canonical hex, then decode it back + const encoded = await callTool(server, 'sails_encode_type', { + program: PROGRAM, + service: 'Counter', + type_name: 'u32', + value: 42, + }); + const hex = json(encoded).hex; + const result = await callTool(server, 'sails_decode_type', { + program: PROGRAM, + service: 'Counter', + type_name: 'u32', + hex, + }); + expect(result.isError).toBeFalsy(); + const data = json(result); + expect(data.type).toBe('u32'); + expect(data.value).toBe(42); + }); + + test('decodes a bool value', async () => { + const result = await callTool(server, 'sails_decode_type', { + program: PROGRAM, + service: 'Counter', + type_name: 'bool', + hex: '0x01', + }); + expect(result.isError).toBeFalsy(); + expect(json(result).value).toBe(true); + }); + + test('encode/decode round-trip for u32', async () => { + const encoded = await callTool(server, 'sails_encode_type', { + program: PROGRAM, + service: 'Counter', + type_name: 'u32', + value: 12345, + }); + const { hex } = json(encoded); + + const decoded = await callTool(server, 'sails_decode_type', { + program: PROGRAM, + service: 'Counter', + type_name: 'u32', + hex, + }); + expect(json(decoded).value).toBe(12345); + }); + + test('returns error for unknown service', async () => { + const result = await callTool(server, 'sails_decode_type', { + program: PROGRAM, + service: 'NoSuchService', + type_name: 'u32', + hex: '0x00000000', + }); + expect(result.isError).toBe(true); + expect(result.content[0].text).toMatch(/NoSuchService/); + }); +}); diff --git a/js/parser-idl-v2/src/index.ts b/js/parser-idl-v2/src/index.ts index cba185229..4f31e2f9a 100644 --- a/js/parser-idl-v2/src/index.ts +++ b/js/parser-idl-v2/src/index.ts @@ -1,4 +1,4 @@ export { SailsIdlParser } from './parser'; export { normalizeIdl } from './idl-v2-impls'; export { InterfaceId } from './interface-id'; -export { SailsMessageHeader } from './header'; +export { SailsMessageHeader, MAGIC_BYTES, HIGHEST_SUPPORTED_VERSION } from './header'; diff --git a/js/src/sails-idl-v2.ts b/js/src/sails-idl-v2.ts index ed13076a4..5ae754830 100644 --- a/js/src/sails-idl-v2.ts +++ b/js/src/sails-idl-v2.ts @@ -1,5 +1,5 @@ import { GearApi, HexString, UserMessageSent } from '@gear-js/api'; -import { u8aToHex } from '@polkadot/util'; +import { u8aToHex, u8aToU8a } from '@polkadot/util'; import type { TypeDecl, @@ -98,6 +98,28 @@ const _getArgsForTxBuilder = (args: any[], params: ISailsFuncArg[]) => { return args.slice(0, params.length); }; +const _assertMatchingHeader = ( + payload: Uint8Array | HexString, + expected: SailsMessageHeader, + target: string, +) => { + const { ok, header } = SailsMessageHeader.tryFromBytes(u8aToU8a(payload)); + if (!ok || !header) { + throw new Error(`Invalid Sails header for ${target}`); + } + + if ( + header.interfaceId.asU64() !== expected.interfaceId.asU64() || + header.entryId !== expected.entryId + ) { + throw new Error( + `Header mismatch for ${target}: expected interface_id=${expected.interfaceId.toString()} ` + + `entry_id=${expected.entryId}, got interface_id=${header.interfaceId.toString()} ` + + `entry_id=${header.entryId}`, + ); + } +}; + export class SailsProgram { private _doc: IIdlDoc; private _typeResolver: TypeResolver; @@ -232,7 +254,12 @@ export class SailsProgram { return payload.toHex(); }, - decodePayload: (bytes: Uint8Array | string) => { + decodePayload: (bytes: Uint8Array | HexString) => { + _assertMatchingHeader(bytes, header, `constructor "${func.name}"`); + if (params.length === 0) { + return {} as T; + } + const payload = this.registry.createType(`([u8; 16], ${params.map((p) => p.type).join(', ')})`, bytes); const result = {} as Record; for (const [i, param] of params.entries()) { @@ -448,6 +475,11 @@ export class SailsService implements ISailsService { return payload.toHex(); }, decodePayload: (bytes: HexString) => { + _assertMatchingHeader(bytes, header, `${service.name}.${func.name}`); + if (params.length === 0) { + return {} as T; + } + const payload = this.registry.createType(`([u8; 16], ${params.map((p) => p.type).join(', ')})`, bytes); const result = {} as Record; for (const [i, param] of params.entries()) { @@ -472,6 +504,7 @@ export class SailsService implements ISailsService { for (const [idx, event] of service.events.entries()) { const entryIdAnn = event.annotations?.find(([k]) => k === 'entry-id'); const entryId = entryIdAnn ? Number(entryIdAnn[1]) : idx; + const header = SailsMessageHeader.v1(InterfaceId.from(service.interface_id), entryId, this.routeIdx); const t = event.fields?.length ? this._typeResolver.getStructDef(event.fields) : 'Null'; const typeStr = event.fields?.length ? this._typeResolver.getStructDef(event.fields, {}, true) : 'Null'; events[event.name] = { @@ -490,6 +523,7 @@ export class SailsService implements ISailsService { return false; }, decode: (payload: HexString) => { + _assertMatchingHeader(payload, header, `${service.name}.${event.name}`); const data = this.registry.createType(`([u8; 16], ${typeStr})`, payload); return data[1].toJSON(); }, From 51dad73bf53d6611d661437f59dcacfa08f8459c Mon Sep 17 00:00:00 2001 From: vobradovich Date: Fri, 3 Apr 2026 12:52:38 +0200 Subject: [PATCH 5/5] fix: tool inputSchema naming --- bun.lock | 39 ++++++++++-- js/mcp-server/src/tools/codec-tools.ts | 6 +- js/mcp-server/tests/tool-args.test.ts | 81 ++++++++++++++++++++++++ js/mcp-server/tests/tool-routing.test.ts | 33 ++++++++++ 4 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 js/mcp-server/tests/tool-args.test.ts diff --git a/bun.lock b/bun.lock index b14e39c12..bbbc379b4 100644 --- a/bun.lock +++ b/bun.lock @@ -93,12 +93,13 @@ "sails-mcp": "./src/index.ts", }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.29.0", "sails-js": "workspace:*", "sails-js-parser-idl-v2": "workspace:*", "sails-js-types": "workspace:*", "sails-js-util": "workspace:*", - "zod": "^3.24.0", + "viem": "^2.0.0", + "zod": "^4.0.0", }, }, "js/parser": { @@ -131,6 +132,8 @@ }, }, "packages": { + "@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="], + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "7.28.5", "js-tokens": "4.0.0", "picocolors": "1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], @@ -327,7 +330,9 @@ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "1.8.1", "@emnapi/runtime": "1.8.1", "@tybys/wasm-util": "0.10.1" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], - "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], + + "@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], @@ -471,6 +476,10 @@ "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], + "@scure/bip32": ["@scure/bip32@1.7.0", "", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], + + "@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], + "@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], @@ -589,6 +598,8 @@ "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], + "abitype": ["abitype@1.2.3", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg=="], + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], @@ -923,6 +934,8 @@ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], + "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], "istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/parser": "7.29.0", "@istanbuljs/schema": "0.1.3", "istanbul-lib-coverage": "3.2.2", "semver": "7.7.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], @@ -1095,6 +1108,8 @@ "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "0.1.4", "fast-levenshtein": "2.0.6", "levn": "0.4.1", "prelude-ls": "1.2.1", "type-check": "0.4.0", "word-wrap": "1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + "ox": ["ox@0.14.7", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-zSQ/cfBdolj7U4++NAvH7sI+VG0T3pEohITCgcQj8KlawvTDY4vGVhDT64Atsm0d6adWfIYHDpu88iUBMMp+AQ=="], + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "3.1.0" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], @@ -1313,6 +1328,8 @@ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "viem": ["viem@2.47.6", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.2.3", "isows": "1.0.7", "ox": "0.14.7", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-zExmbI99NGvMdYa7fmqSTLgkwh48dmhgEqFrUgkpL4kfG4XkVefZ8dZqIKVUhZo6Uhf0FrrEXOsHm9LUyIvI2Q=="], + "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], @@ -1331,7 +1348,7 @@ "write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "0.1.4", "signal-exit": "4.1.0" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - "ws": ["ws@8.19.0", "", {}, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], @@ -1347,7 +1364,7 @@ "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], @@ -1375,12 +1392,16 @@ "@modelcontextprotocol/sdk/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], + "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@polkadot/networks/@polkadot/util": ["@polkadot/util@13.5.9", "", { "dependencies": { "@polkadot/x-bigint": "13.5.9", "@polkadot/x-global": "13.5.9", "@polkadot/x-textdecoder": "13.5.9", "@polkadot/x-textencoder": "13.5.9", "@types/bn.js": "5.2.0", "bn.js": "5.2.3", "tslib": "2.8.1" } }, "sha512-pIK3XYXo7DKeFRkEBNYhf3GbCHg6dKQisSvdzZwuyzA6m7YxQq4DFw4IE464ve4Z7WsJFt3a6C9uII36hl9EWw=="], "@polkadot/rpc-provider/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], "@polkadot/types-codec/@polkadot/x-bigint": ["@polkadot/x-bigint@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" } }, "sha512-JVW6vw3e8fkcRyN9eoc6JIl63MRxNQCP/tuLdHWZts1tcAYao0hpWUzteqJY93AgvmQ91KPsC1Kf3iuuZCi74g=="], + "@polkadot/util-crypto/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + "@polkadot/util-crypto/@polkadot/x-bigint": ["@polkadot/x-bigint@13.5.9", "", { "dependencies": { "@polkadot/x-global": "13.5.9", "tslib": "2.8.1" } }, "sha512-JVW6vw3e8fkcRyN9eoc6JIl63MRxNQCP/tuLdHWZts1tcAYao0hpWUzteqJY93AgvmQ91KPsC1Kf3iuuZCi74g=="], "@polkadot/x-fetch/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], @@ -1389,6 +1410,10 @@ "@polkadot/x-ws/@polkadot/x-global": ["@polkadot/x-global@13.5.9", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA=="], + "@polkadot/x-ws/ws": ["ws@8.19.0", "", {}, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + + "@scure/bip32/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.2", "", { "dependencies": { "brace-expansion": "5.0.3" } }, "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw=="], @@ -1423,6 +1448,8 @@ "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "ox/eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "5.0.0", "path-exists": "4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -1431,6 +1458,8 @@ "rollup-plugin-typescript2/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "2.0.2", "picomatch": "2.3.1" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], + "smoldot/ws": ["ws@8.19.0", "", {}, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], diff --git a/js/mcp-server/src/tools/codec-tools.ts b/js/mcp-server/src/tools/codec-tools.ts index be34d60fe..bf5f31356 100644 --- a/js/mcp-server/src/tools/codec-tools.ts +++ b/js/mcp-server/src/tools/codec-tools.ts @@ -158,12 +158,14 @@ export function registerCodecTools(server: McpServer) { 'Encode a program constructor call to hex. Used for program initialization (upload_program / create_program).', inputSchema: { program: z.string().describe('Registered program name'), - constructor: z.string().describe('Constructor name (e.g. "New", "Default")'), + // Avoid the field name "constructor": MCP arguments are validated as a record, + // and that key is unsafe in the current SDK stack. + ctor: z.string().describe('Constructor name (e.g. "New", "Default")'), args: z.array(z.any()).default([]).describe('Constructor arguments as JSON array'), }, annotations: { readOnlyHint: true }, }, - async ({ program: programName, constructor: ctorName, args }) => { + async ({ program: programName, ctor: ctorName, args }) => { try { const entry = registry.getOrThrow(programName); const ctors = entry.program.ctors; diff --git a/js/mcp-server/tests/tool-args.test.ts b/js/mcp-server/tests/tool-args.test.ts new file mode 100644 index 000000000..b4d139f5b --- /dev/null +++ b/js/mcp-server/tests/tool-args.test.ts @@ -0,0 +1,81 @@ +import { describe, test, expect } from 'bun:test'; +import { z } from 'zod'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { registerAbiTools } from '../src/tools/abi-tools'; +import { registerCodecTools } from '../src/tools/codec-tools'; +import { registerHeaderTools } from '../src/tools/header-tools'; +import { registerIdlTools } from '../src/tools/idl-tools'; +import { registerSourceTools } from '../src/tools/source-tools'; +import { registerTypeTools } from '../src/tools/type-tools'; +import { registerUtilTools } from '../src/tools/util-tools'; + +type ToolListResult = { + tools: Array<{ + name: string; + inputSchema?: { + properties?: Record; + }; + }>; +}; + +function makeServer() { + const server = new McpServer({ name: 'test', version: '0.0.0' }); + registerAbiTools(server); + registerCodecTools(server); + registerHeaderTools(server); + registerIdlTools(server); + registerSourceTools(server); + registerTypeTools(server); + registerUtilTools(server); + return server; +} + +async function listTools(server: McpServer): Promise { + const result = await (server.server as any)._requestHandlers.get('tools/list')( + { + jsonrpc: '2.0', + id: 1, + method: 'tools/list', + params: {}, + }, + {}, + ); + + return result as ToolListResult; +} + +describe('tool arg names', () => { + test('all tool argument names survive MCP record parsing', async () => { + const server = makeServer(); + const listed = await listTools(server); + const recordSchema = z.record(z.string(), z.unknown()); + + const dropped: Array<{ tool: string; expected: string[]; actual: string[] }> = []; + + for (const tool of listed.tools) { + const argNames = Object.keys(tool.inputSchema?.properties ?? {}); + if (argNames.length === 0) { + continue; + } + + const sampleArgs = Object.fromEntries(argNames.map((name) => [name, true])); + const parsed = recordSchema.safeParse(sampleArgs); + expect(parsed.success).toBeTrue(); + + if (!parsed.success) { + continue; + } + + const actualNames = Object.keys(parsed.data); + if (actualNames.length !== argNames.length || actualNames.some((name, i) => name !== argNames[i])) { + dropped.push({ + tool: tool.name, + expected: argNames, + actual: actualNames, + }); + } + } + + expect(dropped).toEqual([]); + }); +}); diff --git a/js/mcp-server/tests/tool-routing.test.ts b/js/mcp-server/tests/tool-routing.test.ts index 034c7d0e1..ba5f8bd83 100644 --- a/js/mcp-server/tests/tool-routing.test.ts +++ b/js/mcp-server/tests/tool-routing.test.ts @@ -28,6 +28,23 @@ async function callTool(server: McpServer, name: string, args: Record, +): Promise { + const result = await (server.server as any)._requestHandlers.get('tools/call')( + { + jsonrpc: '2.0', + id: 1, + method: 'tools/call', + params: { name, arguments: args }, + }, + {}, + ); + return result as ToolResult; +} + function json(result: ToolResult) { return JSON.parse(result.content[0].text); } @@ -91,4 +108,20 @@ describe('tool routing', () => { auto_detected: true, }); }); + + test('sails_encode_constructor works through MCP protocol using ctor argument', async () => { + const entry = registry.getOrThrow(PROGRAM); + const expected = entry.program.ctors?.Default.encodePayload(); + + const result = await callToolViaProtocol(server, 'sails_encode_constructor', { + program: PROGRAM, + ctor: 'Default', + args: [], + }); + + expect(result.isError).toBeFalsy(); + expect(json(result)).toMatchObject({ + hex: expected, + }); + }); });