diff --git a/.eslintrc.json b/.eslintrc.json index b707bc3..0483701 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,18 +1,15 @@ { - "parser": "@typescript-eslint/parser", - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "plugins": ["@typescript-eslint"], - "env": { - "node": true, - "es2022": true - }, - "rules": { - "no-console": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }] - } - } \ No newline at end of file + "parser": "@typescript-eslint/parser", + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "plugins": ["@typescript-eslint"], + "env": { + "node": true, + "es2022": true + }, + "rules": { + "no-console": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }] + } +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..b5c68e5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,7 +4,6 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' - --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md index 48d5f81..96a4735 100644 --- a/.github/ISSUE_TEMPLATE/custom.md +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -4,7 +4,4 @@ about: Describe this issue template's purpose here. title: '' labels: '' assignees: '' - --- - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..2f28cea 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,7 +4,6 @@ about: Suggest an idea for this project title: '' labels: '' assignees: '' - --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index bebc36b..ced66b9 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -23,7 +23,7 @@ jobs: with: node-version: '20' registry-url: 'https://registry.npmjs.org' - cache: 'npm' # Enables npm dependency caching + cache: 'npm' # Enables npm dependency caching cache-dependency-path: '**/package-lock.json' # Cache key based on lockfile - name: Install dependencies diff --git a/.prettierrc b/.prettierrc index 0c6a633..3de448e 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,7 @@ { - "semi": true, - "trailingComma": "es5", - "singleQuote": true, - "printWidth": 100, - "tabWidth": 2 - } \ No newline at end of file + "semi": true, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2 +} diff --git a/CHANGELOG.md b/CHANGELOG.md index e5d2d88..6db8a35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,23 +8,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.1.2] - 2025-06-08 ### Fixed + - Prevent stack overflow (RangeError: Maximum call stack size exceeded) when processing recursive or cyclic OpenAPI schemas (e.g., self-referencing objects). - Added cycle detection to schema mapping, ensuring robust handling of recursive structures. ## [3.1.1] - 2025-05-26 ### Added + - Introduced a new executable command-line script for easier usage in Unix-like environments. ### Changed + - Use new CLI entry point to use the new `bin/openapi-mcp-generator.js` file. - Updated build script to ensure the new CLI file has the correct permissions. - Refactored `index.ts` to streamline argument parsing and error handling. - ## [3.1.0] - 2025-05-18 ### Added + - Programmatic API to extract MCP tool definitions from OpenAPI specs - New exportable `getToolsFromOpenApi` function for direct integration in code - Advanced filtering capabilities for programmatic tool extraction @@ -32,20 +35,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated README with programmatic API usage examples ### Changed + - Improved module structure with better exports - Enhanced detection of module execution context ## [3.0.0] - 2025-04-26 ### Added + - Streamable HTTP support for OpenAPI MCP generator, enabling efficient handling of large payloads and real-time data transfer. - Major architectural refactor to support streaming responses and requests. ### Fixed + - Multiple bugs related to HTTP/HTTPS connection handling, stream closure, and error propagation in streaming scenarios. - Fixed resource leak issues on server aborts and client disconnects during streaming. ### Changed + - Major version bump due to breaking changes in API and internal structures to support streaming. - Updated documentation to reflect new streaming capabilities and usage instructions. - Enhanced performance and robustness of HTTP/HTTPS transport layers. @@ -53,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2.0.0] - 2025-04-12 ### Added + - Runtime argument validation using Zod - JSON Schema to Zod schema conversion - Improved error handling and formatting @@ -63,6 +71,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for multiple content types ### Changed + - Simplified transport layer to only support stdio transport - Removed support for WebSocket and HTTP transports - Updated to use @modelcontextprotocol/sdk v1.9.0 @@ -72,6 +81,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - More robust OpenAPI schema processing ### Fixed + - Path parameter resolution in URLs - Content-Type header handling - Response processing for different content types @@ -81,6 +91,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.0] - Initial Release ### Added + - Basic OpenAPI to MCP server generation - Support for GET, POST, PUT, DELETE methods - Basic error handling diff --git a/PROGRAMMATIC_API.md b/PROGRAMMATIC_API.md index 33517cf..3e16400 100644 --- a/PROGRAMMATIC_API.md +++ b/PROGRAMMATIC_API.md @@ -21,16 +21,19 @@ import { getToolsFromOpenApi } from 'openapi-mcp-generator'; This function extracts an array of tools from an OpenAPI specification. **Parameters:** + - `specPathOrUrl`: Path to a local OpenAPI spec file or URL to a remote spec - `options`: (Optional) Configuration options **Options:** + - `baseUrl`: Override the base URL in the OpenAPI spec - `dereference`: Whether to resolve $refs (default: false) - `excludeOperationIds`: Array of operation IDs to exclude from the results - `filterFn`: Custom function to filter tools (receives tool, returns boolean) **Returns:** + - Promise that resolves to an array of McpToolDefinition objects **Example:** @@ -42,12 +45,15 @@ import { getToolsFromOpenApi } from 'openapi-mcp-generator'; const tools = await getToolsFromOpenApi('./petstore.json'); // With options -const filteredTools = await getToolsFromOpenApi('https://petstore3.swagger.io/api/v3/openapi.json', { - baseUrl: 'https://petstore3.swagger.io/api/v3', - dereference: true, - excludeOperationIds: ['addPet', 'updatePet'], - filterFn: (tool) => tool.method.toLowerCase() === 'get' -}); +const filteredTools = await getToolsFromOpenApi( + 'https://petstore3.swagger.io/api/v3/openapi.json', + { + baseUrl: 'https://petstore3.swagger.io/api/v3', + dereference: true, + excludeOperationIds: ['addPet', 'updatePet'], + filterFn: (tool) => tool.method.toLowerCase() === 'get', + } +); // Process the results for (const tool of filteredTools) { @@ -66,34 +72,34 @@ Each tool definition (`McpToolDefinition`) has the following properties: interface McpToolDefinition { /** Name of the tool, must be unique */ name: string; - + /** Human-readable description of the tool */ description: string; - + /** JSON Schema that defines the input parameters */ inputSchema: JSONSchema7 | boolean; - + /** HTTP method for the operation (get, post, etc.) */ method: string; - + /** URL path template with parameter placeholders */ pathTemplate: string; - + /** OpenAPI parameter objects for this operation */ parameters: OpenAPIV3.ParameterObject[]; - + /** Parameter names and locations for execution */ executionParameters: { name: string; in: string }[]; - + /** Content type for request body, if applicable */ requestBodyContentType?: string; - + /** Security requirements for this operation */ securityRequirements: OpenAPIV3.SecurityRequirementObject[]; - + /** Original operation ID from the OpenAPI spec */ operationId: string; - + /** Base URL for the API (if available) */ baseUrl?: string; } @@ -105,7 +111,7 @@ interface McpToolDefinition { ```typescript const getTools = await getToolsFromOpenApi(specUrl, { - filterFn: (tool) => tool.method.toLowerCase() === 'get' + filterFn: (tool) => tool.method.toLowerCase() === 'get', }); ``` @@ -113,7 +119,7 @@ const getTools = await getToolsFromOpenApi(specUrl, { ```typescript const secureTools = await getToolsFromOpenApi(specUrl, { - filterFn: (tool) => tool.securityRequirements.length > 0 + filterFn: (tool) => tool.securityRequirements.length > 0, }); ``` @@ -121,7 +127,7 @@ const secureTools = await getToolsFromOpenApi(specUrl, { ```typescript const userTools = await getToolsFromOpenApi(specUrl, { - filterFn: (tool) => tool.pathTemplate.includes('/user') + filterFn: (tool) => tool.pathTemplate.includes('/user'), }); ``` @@ -130,8 +136,6 @@ const userTools = await getToolsFromOpenApi(specUrl, { ```typescript const safeUserTools = await getToolsFromOpenApi(specUrl, { excludeOperationIds: ['deleteUser', 'updateUser'], - filterFn: (tool) => - tool.pathTemplate.includes('/user') && - tool.method.toLowerCase() === 'get' + filterFn: (tool) => tool.pathTemplate.includes('/user') && tool.method.toLowerCase() === 'get', }); -``` \ No newline at end of file +``` diff --git a/bin/openapi-mcp-generator.js b/bin/openapi-mcp-generator.js index 3f1bb95..c42eee0 100755 --- a/bin/openapi-mcp-generator.js +++ b/bin/openapi-mcp-generator.js @@ -3,4 +3,4 @@ import { program } from '../dist/index.js'; // Parse CLI arguments and run the program -program.parse(process.argv); \ No newline at end of file +program.parse(process.argv); diff --git a/examples/pet-store-sse/.eslintrc.json b/examples/pet-store-sse/.eslintrc.json index 8cb5c8e..2c368f9 100644 --- a/examples/pet-store-sse/.eslintrc.json +++ b/examples/pet-store-sse/.eslintrc.json @@ -1,12 +1,7 @@ { "parser": "@typescript-eslint/parser", - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "plugins": [ - "@typescript-eslint" - ], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "plugins": ["@typescript-eslint"], "env": { "node": true, "es2022": true @@ -15,10 +10,7 @@ "no-console": [ "error", { - "allow": [ - "error", - "warn" - ] + "allow": ["error", "warn"] } ], "@typescript-eslint/explicit-function-return-type": "off", @@ -30,4 +22,4 @@ } ] } -} \ No newline at end of file +} diff --git a/examples/pet-store-sse/.prettierrc b/examples/pet-store-sse/.prettierrc index 494b947..3de448e 100644 --- a/examples/pet-store-sse/.prettierrc +++ b/examples/pet-store-sse/.prettierrc @@ -4,4 +4,4 @@ "singleQuote": true, "printWidth": 100, "tabWidth": 2 -} \ No newline at end of file +} diff --git a/examples/pet-store-sse/docs/oauth2-configuration.md b/examples/pet-store-sse/docs/oauth2-configuration.md index 9f3625b..1a5a040 100644 --- a/examples/pet-store-sse/docs/oauth2-configuration.md +++ b/examples/pet-store-sse/docs/oauth2-configuration.md @@ -13,11 +13,13 @@ This API uses OAuth2 for authentication. The MCP server can handle OAuth2 authen - `OAUTH_CLIENT_ID_PETSTORE_AUTH`: Your OAuth client ID - `OAUTH_CLIENT_SECRET_PETSTORE_AUTH`: Your OAuth client secret + ## Token Caching The MCP server automatically caches OAuth tokens obtained via client credentials flow. Tokens are cached for their lifetime (as specified by the `expires_in` parameter in the token response) minus 60 seconds as a safety margin. When making API requests, the server will: + 1. Check for a cached token that's still valid 2. Use the cached token if available 3. Request a new token if no valid cached token exists diff --git a/examples/pet-store-sse/package.json b/examples/pet-store-sse/package.json index 13ef081..d94f636 100644 --- a/examples/pet-store-sse/package.json +++ b/examples/pet-store-sse/package.json @@ -34,4 +34,4 @@ "typescript": "^5.8.3", "@types/uuid": "^10.0.0" } -} \ No newline at end of file +} diff --git a/examples/pet-store-sse/public/index.html b/examples/pet-store-sse/public/index.html index aa97ea3..9b4213e 100644 --- a/examples/pet-store-sse/public/index.html +++ b/examples/pet-store-sse/public/index.html @@ -1,393 +1,406 @@ - + - - - -swagger-petstore---openapi-3-0 MCP Test Client - - - -

swagger-petstore---openapi-3-0 MCP Test Client

-

Disconnected

- -
-
- -
- - -
-
- - - -
-
-

Debug Console

- -
-
-
- - - - \ No newline at end of file + + // Try to parse arguments from user input + // Format: toolName param1=value1 param2=value2 + function parseArguments(text) { + const parts = text.split(' '); + if (parts.length <= 1) return {}; + + const args = {}; + // Skip the first part (tool name) and process the rest + for (let i = 1; i < parts.length; i++) { + const part = parts[i]; + const equalsIndex = part.indexOf('='); + + if (equalsIndex > 0) { + const key = part.substring(0, equalsIndex); + const value = part.substring(equalsIndex + 1); + + // Try to parse as number or boolean if possible + if (value === 'true') args[key] = true; + else if (value === 'false') args[key] = false; + else if (!isNaN(Number(value))) args[key] = Number(value); + else args[key] = value; + } + } + + return args; + } + + // Add a message to the conversation + function appendMessage(sender, text) { + const messageDiv = document.createElement('div'); + messageDiv.className = `message ${sender}`; + + // Format as code block if it looks like JSON + if (text.trim().startsWith('{') || text.trim().startsWith('[')) { + const pre = document.createElement('pre'); + const code = document.createElement('code'); + code.textContent = text; + pre.appendChild(code); + messageDiv.appendChild(pre); + } else { + messageDiv.textContent = text; + } + + conversation.appendChild(messageDiv); + conversation.scrollTop = conversation.scrollHeight; + } + + // Event listeners + sendButton.addEventListener('click', sendMessage); + userInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') sendMessage(); + }); + + // Connect on page load + appendMessage('system', 'Connecting to server...'); + connect(); + + // Clean up on page unload + window.addEventListener('beforeunload', () => { + if (eventSource) eventSource.close(); + }); + + + diff --git a/examples/pet-store-sse/src/index.ts b/examples/pet-store-sse/src/index.ts index 1a7673a..8ea28d4 100644 --- a/examples/pet-store-sse/src/index.ts +++ b/examples/pet-store-sse/src/index.ts @@ -8,16 +8,16 @@ import dotenv from 'dotenv'; dotenv.config(); -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, type Tool, type CallToolResult, - type CallToolRequest -} from "@modelcontextprotocol/sdk/types.js"; -import { setupWebServer } from "./web-server.js"; + type CallToolRequest, +} from '@modelcontextprotocol/sdk/types.js'; +import { setupWebServer } from './web-server.js'; import { z, ZodError } from 'zod'; import { jsonSchemaToZod } from 'json-schema-to-zod'; @@ -32,386 +32,695 @@ type JsonObject = Record; * Interface for MCP Tool Definition */ interface McpToolDefinition { - name: string; - description: string; - inputSchema: any; - method: string; - pathTemplate: string; - executionParameters: { name: string, in: string }[]; - requestBodyContentType?: string; - securityRequirements: any[]; + name: string; + description: string; + inputSchema: any; + method: string; + pathTemplate: string; + executionParameters: { name: string; in: string }[]; + requestBodyContentType?: string; + securityRequirements: any[]; } /** * Server configuration */ -export const SERVER_NAME = "swagger-petstore---openapi-3-0"; -export const SERVER_VERSION = "1.0.26"; -export const API_BASE_URL = "https://petstore3.swagger.io/api/v3"; +export const SERVER_NAME = 'swagger-petstore---openapi-3-0'; +export const SERVER_VERSION = '1.0.26'; +export const API_BASE_URL = 'https://petstore3.swagger.io/api/v3'; /** * MCP Server instance */ const server = new Server( - { name: SERVER_NAME, version: SERVER_VERSION }, - { capabilities: { tools: {} } } + { name: SERVER_NAME, version: SERVER_VERSION }, + { capabilities: { tools: {} } } ); /** * Map of tool definitions by name */ const toolDefinitionMap: Map = new Map([ - - ["updatepet", { - name: "updatepet", - description: `Update an existing pet by Id.`, - inputSchema: {"type":"object","properties":{"requestBody":{"required":["name","photoUrls"],"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"},"category":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}},"photoUrls":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"description":"Update an existent pet in the store"}},"required":["requestBody"]}, - method: "put", - pathTemplate: "/pet", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["addpet", { - name: "addpet", - description: `Add a new pet to the store.`, - inputSchema: {"type":"object","properties":{"requestBody":{"required":["name","photoUrls"],"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"},"category":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}},"photoUrls":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"description":"Create a new pet in the store"}},"required":["requestBody"]}, - method: "post", - pathTemplate: "/pet", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["findpetsbystatus", { - name: "findpetsbystatus", - description: `Multiple status values can be provided with comma separated strings.`, - inputSchema: {"type":"object","properties":{"status":{"type":"string","default":"available","enum":["available","pending","sold"],"description":"Status values that need to be considered for filter"}}}, - method: "get", - pathTemplate: "/pet/findByStatus", - executionParameters: [{"name":"status","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["findpetsbytags", { - name: "findpetsbytags", - description: `Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.`, - inputSchema: {"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"},"description":"Tags to filter by"}}}, - method: "get", - pathTemplate: "/pet/findByTags", - executionParameters: [{"name":"tags","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["getpetbyid", { - name: "getpetbyid", - description: `Returns a single pet.`, - inputSchema: {"type":"object","properties":{"petId":{"type":"number","format":"int64","description":"ID of pet to return"}},"required":["petId"]}, - method: "get", - pathTemplate: "/pet/{petId}", - executionParameters: [{"name":"petId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [{"api_key":[]},{"petstore_auth":["write:pets","read:pets"]}] - }], - ["updatepetwithform", { - name: "updatepetwithform", - description: `Updates a pet resource based on the form data.`, - inputSchema: {"type":"object","properties":{"petId":{"type":"number","format":"int64","description":"ID of pet that needs to be updated"},"name":{"type":"string","description":"Name of pet that needs to be updated"},"status":{"type":"string","description":"Status of pet that needs to be updated"}},"required":["petId"]}, - method: "post", - pathTemplate: "/pet/{petId}", - executionParameters: [{"name":"petId","in":"path"},{"name":"name","in":"query"},{"name":"status","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["deletepet", { - name: "deletepet", - description: `Delete a pet.`, - inputSchema: {"type":"object","properties":{"api_key":{"type":"string"},"petId":{"type":"number","format":"int64","description":"Pet id to delete"}},"required":["petId"]}, - method: "delete", - pathTemplate: "/pet/{petId}", - executionParameters: [{"name":"api_key","in":"header"},{"name":"petId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["uploadfile", { - name: "uploadfile", - description: `Upload image of the pet.`, - inputSchema: {"type":"object","properties":{"petId":{"type":"number","format":"int64","description":"ID of pet to update"},"additionalMetadata":{"type":"string","description":"Additional Metadata"},"requestBody":{"type":"string","description":"Request body (content type: application/octet-stream)"}},"required":["petId"]}, - method: "post", - pathTemplate: "/pet/{petId}/uploadImage", - executionParameters: [{"name":"petId","in":"path"},{"name":"additionalMetadata","in":"query"}], - requestBodyContentType: "application/octet-stream", - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["getinventory", { - name: "getinventory", - description: `Returns a map of status codes to quantities.`, - inputSchema: {"type":"object","properties":{}}, - method: "get", - pathTemplate: "/store/inventory", - executionParameters: [], - requestBodyContentType: undefined, - securityRequirements: [{"api_key":[]}] - }], - ["placeorder", { - name: "placeorder", - description: `Place a new order in the store.`, - inputSchema: {"type":"object","properties":{"requestBody":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"petId":{"type":"number","format":"int64"},"quantity":{"type":"number","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean"}},"description":"The JSON request body."}}}, - method: "post", - pathTemplate: "/store/order", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["getorderbyid", { - name: "getorderbyid", - description: `For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.`, - inputSchema: {"type":"object","properties":{"orderId":{"type":"number","format":"int64","description":"ID of order that needs to be fetched"}},"required":["orderId"]}, - method: "get", - pathTemplate: "/store/order/{orderId}", - executionParameters: [{"name":"orderId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["deleteorder", { - name: "deleteorder", - description: `For valid response try integer IDs with value < 1000. Anything above 1000 or non-integers will generate API errors.`, - inputSchema: {"type":"object","properties":{"orderId":{"type":"number","format":"int64","description":"ID of the order that needs to be deleted"}},"required":["orderId"]}, - method: "delete", - pathTemplate: "/store/order/{orderId}", - executionParameters: [{"name":"orderId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["createuser", { - name: "createuser", - description: `This can only be done by the logged in user.`, - inputSchema: {"type":"object","properties":{"requestBody":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"number","description":"User Status","format":"int32"}},"description":"Created user object"}}}, - method: "post", - pathTemplate: "/user", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["createuserswithlistinput", { - name: "createuserswithlistinput", - description: `Creates list of users with given input array.`, - inputSchema: {"type":"object","properties":{"requestBody":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"number","description":"User Status","format":"int32"}}},"description":"The JSON request body."}}}, - method: "post", - pathTemplate: "/user/createWithList", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["loginuser", { - name: "loginuser", - description: `Log into the system.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"The user name for login"},"password":{"type":"string","description":"The password for login in clear text"}}}, - method: "get", - pathTemplate: "/user/login", - executionParameters: [{"name":"username","in":"query"},{"name":"password","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["logoutuser", { - name: "logoutuser", - description: `Log user out of the system.`, - inputSchema: {"type":"object","properties":{}}, - method: "get", - pathTemplate: "/user/logout", - executionParameters: [], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["getuserbyname", { - name: "getuserbyname", - description: `Get user detail based on username.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"The name that needs to be fetched. Use user1 for testing"}},"required":["username"]}, - method: "get", - pathTemplate: "/user/{username}", - executionParameters: [{"name":"username","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["updateuser", { - name: "updateuser", - description: `This can only be done by the logged in user.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"name that need to be deleted"},"requestBody":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"number","description":"User Status","format":"int32"}},"description":"Update an existent user in the store"}},"required":["username"]}, - method: "put", - pathTemplate: "/user/{username}", - executionParameters: [{"name":"username","in":"path"}], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["deleteuser", { - name: "deleteuser", - description: `This can only be done by the logged in user.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"The name that needs to be deleted"}},"required":["username"]}, - method: "delete", - pathTemplate: "/user/{username}", - executionParameters: [{"name":"username","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], + [ + 'updatepet', + { + name: 'updatepet', + description: `Update an existing pet by Id.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + required: ['name', 'photoUrls'], + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + name: { type: 'string' }, + category: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + photoUrls: { type: 'array', items: { type: 'string' } }, + tags: { + type: 'array', + items: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + }, + status: { + type: 'string', + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + }, + }, + description: 'Update an existent pet in the store', + }, + }, + required: ['requestBody'], + }, + method: 'put', + pathTemplate: '/pet', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'addpet', + { + name: 'addpet', + description: `Add a new pet to the store.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + required: ['name', 'photoUrls'], + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + name: { type: 'string' }, + category: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + photoUrls: { type: 'array', items: { type: 'string' } }, + tags: { + type: 'array', + items: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + }, + status: { + type: 'string', + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + }, + }, + description: 'Create a new pet in the store', + }, + }, + required: ['requestBody'], + }, + method: 'post', + pathTemplate: '/pet', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'findpetsbystatus', + { + name: 'findpetsbystatus', + description: `Multiple status values can be provided with comma separated strings.`, + inputSchema: { + type: 'object', + properties: { + status: { + type: 'string', + default: 'available', + enum: ['available', 'pending', 'sold'], + description: 'Status values that need to be considered for filter', + }, + }, + }, + method: 'get', + pathTemplate: '/pet/findByStatus', + executionParameters: [{ name: 'status', in: 'query' }], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'findpetsbytags', + { + name: 'findpetsbytags', + description: `Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.`, + inputSchema: { + type: 'object', + properties: { + tags: { type: 'array', items: { type: 'string' }, description: 'Tags to filter by' }, + }, + }, + method: 'get', + pathTemplate: '/pet/findByTags', + executionParameters: [{ name: 'tags', in: 'query' }], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'getpetbyid', + { + name: 'getpetbyid', + description: `Returns a single pet.`, + inputSchema: { + type: 'object', + properties: { + petId: { type: 'number', format: 'int64', description: 'ID of pet to return' }, + }, + required: ['petId'], + }, + method: 'get', + pathTemplate: '/pet/{petId}', + executionParameters: [{ name: 'petId', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [{ api_key: [] }, { petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'updatepetwithform', + { + name: 'updatepetwithform', + description: `Updates a pet resource based on the form data.`, + inputSchema: { + type: 'object', + properties: { + petId: { + type: 'number', + format: 'int64', + description: 'ID of pet that needs to be updated', + }, + name: { type: 'string', description: 'Name of pet that needs to be updated' }, + status: { type: 'string', description: 'Status of pet that needs to be updated' }, + }, + required: ['petId'], + }, + method: 'post', + pathTemplate: '/pet/{petId}', + executionParameters: [ + { name: 'petId', in: 'path' }, + { name: 'name', in: 'query' }, + { name: 'status', in: 'query' }, + ], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'deletepet', + { + name: 'deletepet', + description: `Delete a pet.`, + inputSchema: { + type: 'object', + properties: { + api_key: { type: 'string' }, + petId: { type: 'number', format: 'int64', description: 'Pet id to delete' }, + }, + required: ['petId'], + }, + method: 'delete', + pathTemplate: '/pet/{petId}', + executionParameters: [ + { name: 'api_key', in: 'header' }, + { name: 'petId', in: 'path' }, + ], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'uploadfile', + { + name: 'uploadfile', + description: `Upload image of the pet.`, + inputSchema: { + type: 'object', + properties: { + petId: { type: 'number', format: 'int64', description: 'ID of pet to update' }, + additionalMetadata: { type: 'string', description: 'Additional Metadata' }, + requestBody: { + type: 'string', + description: 'Request body (content type: application/octet-stream)', + }, + }, + required: ['petId'], + }, + method: 'post', + pathTemplate: '/pet/{petId}/uploadImage', + executionParameters: [ + { name: 'petId', in: 'path' }, + { name: 'additionalMetadata', in: 'query' }, + ], + requestBodyContentType: 'application/octet-stream', + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'getinventory', + { + name: 'getinventory', + description: `Returns a map of status codes to quantities.`, + inputSchema: { type: 'object', properties: {} }, + method: 'get', + pathTemplate: '/store/inventory', + executionParameters: [], + requestBodyContentType: undefined, + securityRequirements: [{ api_key: [] }], + }, + ], + [ + 'placeorder', + { + name: 'placeorder', + description: `Place a new order in the store.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + petId: { type: 'number', format: 'int64' }, + quantity: { type: 'number', format: 'int32' }, + shipDate: { type: 'string', format: 'date-time' }, + status: { + type: 'string', + description: 'Order Status', + enum: ['placed', 'approved', 'delivered'], + }, + complete: { type: 'boolean' }, + }, + description: 'The JSON request body.', + }, + }, + }, + method: 'post', + pathTemplate: '/store/order', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'getorderbyid', + { + name: 'getorderbyid', + description: `For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.`, + inputSchema: { + type: 'object', + properties: { + orderId: { + type: 'number', + format: 'int64', + description: 'ID of order that needs to be fetched', + }, + }, + required: ['orderId'], + }, + method: 'get', + pathTemplate: '/store/order/{orderId}', + executionParameters: [{ name: 'orderId', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'deleteorder', + { + name: 'deleteorder', + description: `For valid response try integer IDs with value < 1000. Anything above 1000 or non-integers will generate API errors.`, + inputSchema: { + type: 'object', + properties: { + orderId: { + type: 'number', + format: 'int64', + description: 'ID of the order that needs to be deleted', + }, + }, + required: ['orderId'], + }, + method: 'delete', + pathTemplate: '/store/order/{orderId}', + executionParameters: [{ name: 'orderId', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'createuser', + { + name: 'createuser', + description: `This can only be done by the logged in user.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + username: { type: 'string' }, + firstName: { type: 'string' }, + lastName: { type: 'string' }, + email: { type: 'string' }, + password: { type: 'string' }, + phone: { type: 'string' }, + userStatus: { type: 'number', description: 'User Status', format: 'int32' }, + }, + description: 'Created user object', + }, + }, + }, + method: 'post', + pathTemplate: '/user', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'createuserswithlistinput', + { + name: 'createuserswithlistinput', + description: `Creates list of users with given input array.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + username: { type: 'string' }, + firstName: { type: 'string' }, + lastName: { type: 'string' }, + email: { type: 'string' }, + password: { type: 'string' }, + phone: { type: 'string' }, + userStatus: { type: 'number', description: 'User Status', format: 'int32' }, + }, + }, + description: 'The JSON request body.', + }, + }, + }, + method: 'post', + pathTemplate: '/user/createWithList', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'loginuser', + { + name: 'loginuser', + description: `Log into the system.`, + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'The user name for login' }, + password: { type: 'string', description: 'The password for login in clear text' }, + }, + }, + method: 'get', + pathTemplate: '/user/login', + executionParameters: [ + { name: 'username', in: 'query' }, + { name: 'password', in: 'query' }, + ], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'logoutuser', + { + name: 'logoutuser', + description: `Log user out of the system.`, + inputSchema: { type: 'object', properties: {} }, + method: 'get', + pathTemplate: '/user/logout', + executionParameters: [], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'getuserbyname', + { + name: 'getuserbyname', + description: `Get user detail based on username.`, + inputSchema: { + type: 'object', + properties: { + username: { + type: 'string', + description: 'The name that needs to be fetched. Use user1 for testing', + }, + }, + required: ['username'], + }, + method: 'get', + pathTemplate: '/user/{username}', + executionParameters: [{ name: 'username', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'updateuser', + { + name: 'updateuser', + description: `This can only be done by the logged in user.`, + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'name that need to be deleted' }, + requestBody: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + username: { type: 'string' }, + firstName: { type: 'string' }, + lastName: { type: 'string' }, + email: { type: 'string' }, + password: { type: 'string' }, + phone: { type: 'string' }, + userStatus: { type: 'number', description: 'User Status', format: 'int32' }, + }, + description: 'Update an existent user in the store', + }, + }, + required: ['username'], + }, + method: 'put', + pathTemplate: '/user/{username}', + executionParameters: [{ name: 'username', in: 'path' }], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'deleteuser', + { + name: 'deleteuser', + description: `This can only be done by the logged in user.`, + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'The name that needs to be deleted' }, + }, + required: ['username'], + }, + method: 'delete', + pathTemplate: '/user/{username}', + executionParameters: [{ name: 'username', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], ]); /** * Security schemes from the OpenAPI spec */ -const securitySchemes = { - "petstore_auth": { - "type": "oauth2", - "flows": { - "implicit": { - "authorizationUrl": "https://petstore3.swagger.io/oauth/authorize", - "scopes": { - "write:pets": "modify pets in your account", - "read:pets": "read your pets" - } - } - } +const securitySchemes = { + petstore_auth: { + type: 'oauth2', + flows: { + implicit: { + authorizationUrl: 'https://petstore3.swagger.io/oauth/authorize', + scopes: { + 'write:pets': 'modify pets in your account', + 'read:pets': 'read your pets', + }, + }, }, - "api_key": { - "type": "apiKey", - "name": "api_key", - "in": "header" - } - }; - + }, + api_key: { + type: 'apiKey', + name: 'api_key', + in: 'header', + }, +}; server.setRequestHandler(ListToolsRequestSchema, async () => { - const toolsForClient: Tool[] = Array.from(toolDefinitionMap.values()).map(def => ({ + const toolsForClient: Tool[] = Array.from(toolDefinitionMap.values()).map((def) => ({ name: def.name, description: def.description, - inputSchema: def.inputSchema + inputSchema: def.inputSchema, })); return { tools: toolsForClient }; }); - -server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest): Promise => { - const { name: toolName, arguments: toolArgs } = request.params; - const toolDefinition = toolDefinitionMap.get(toolName); - if (!toolDefinition) { - console.error(`Error: Unknown tool requested: ${toolName}`); - return { content: [{ type: "text", text: `Error: Unknown tool requested: ${toolName}` }] }; +server.setRequestHandler( + CallToolRequestSchema, + async (request: CallToolRequest): Promise => { + const { name: toolName, arguments: toolArgs } = request.params; + const toolDefinition = toolDefinitionMap.get(toolName); + if (!toolDefinition) { + console.error(`Error: Unknown tool requested: ${toolName}`); + return { content: [{ type: 'text', text: `Error: Unknown tool requested: ${toolName}` }] }; + } + return await executeApiTool(toolName, toolDefinition, toolArgs ?? {}, securitySchemes); } - return await executeApiTool(toolName, toolDefinition, toolArgs ?? {}, securitySchemes); -}); - - +); /** * Type definition for cached OAuth tokens */ interface TokenCacheEntry { - token: string; - expiresAt: number; + token: string; + expiresAt: number; } /** * Declare global __oauthTokenCache property for TypeScript */ declare global { - var __oauthTokenCache: Record | undefined; + var __oauthTokenCache: Record | undefined; } /** * Acquires an OAuth2 token using client credentials flow - * + * * @param schemeName Name of the security scheme * @param scheme OAuth2 security scheme * @returns Acquired token or null if unable to acquire */ -async function acquireOAuth2Token(schemeName: string, scheme: any): Promise { - try { - // Check if we have the necessary credentials - const clientId = process.env[`OAUTH_CLIENT_ID_SCHEMENAME`]; - const clientSecret = process.env[`OAUTH_CLIENT_SECRET_SCHEMENAME`]; - const scopes = process.env[`OAUTH_SCOPES_SCHEMENAME`]; - - if (!clientId || !clientSecret) { - console.error(`Missing client credentials for OAuth2 scheme '${schemeName}'`); - return null; - } - - // Initialize token cache if needed - if (typeof global.__oauthTokenCache === 'undefined') { - global.__oauthTokenCache = {}; - } - - // Check if we have a cached token - const cacheKey = `${schemeName}_${clientId}`; - const cachedToken = global.__oauthTokenCache[cacheKey]; - const now = Date.now(); - - if (cachedToken && cachedToken.expiresAt > now) { - console.error(`Using cached OAuth2 token for '${schemeName}' (expires in ${Math.floor((cachedToken.expiresAt - now) / 1000)} seconds)`); - return cachedToken.token; - } - - // Determine token URL based on flow type - let tokenUrl = ''; - if (scheme.flows?.clientCredentials?.tokenUrl) { - tokenUrl = scheme.flows.clientCredentials.tokenUrl; - console.error(`Using client credentials flow for '${schemeName}'`); - } else if (scheme.flows?.password?.tokenUrl) { - tokenUrl = scheme.flows.password.tokenUrl; - console.error(`Using password flow for '${schemeName}'`); - } else { - console.error(`No supported OAuth2 flow found for '${schemeName}'`); - return null; - } - - // Prepare the token request - let formData = new URLSearchParams(); - formData.append('grant_type', 'client_credentials'); - - // Add scopes if specified - if (scopes) { - formData.append('scope', scopes); - } - - console.error(`Requesting OAuth2 token from ${tokenUrl}`); - - // Make the token request - const response = await axios({ - method: 'POST', - url: tokenUrl, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Authorization': `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}` - }, - data: formData.toString() - }); - - // Process the response - if (response.data?.access_token) { - const token = response.data.access_token; - const expiresIn = response.data.expires_in || 3600; // Default to 1 hour - - // Cache the token - global.__oauthTokenCache[cacheKey] = { - token, - expiresAt: now + (expiresIn * 1000) - 60000 // Expire 1 minute early - }; - - console.error(`Successfully acquired OAuth2 token for '${schemeName}' (expires in ${expiresIn} seconds)`); - return token; - } else { - console.error(`Failed to acquire OAuth2 token for '${schemeName}': No access_token in response`); - return null; - } - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : String(error); - console.error(`Error acquiring OAuth2 token for '${schemeName}':`, errorMessage); - return null; - } -} +async function acquireOAuth2Token( + schemeName: string, + scheme: any +): Promise { + try { + // Check if we have the necessary credentials + const clientId = process.env[`OAUTH_CLIENT_ID_SCHEMENAME`]; + const clientSecret = process.env[`OAUTH_CLIENT_SECRET_SCHEMENAME`]; + const scopes = process.env[`OAUTH_SCOPES_SCHEMENAME`]; + if (!clientId || !clientSecret) { + console.error(`Missing client credentials for OAuth2 scheme '${schemeName}'`); + return null; + } + + // Initialize token cache if needed + if (typeof global.__oauthTokenCache === 'undefined') { + global.__oauthTokenCache = {}; + } + + // Check if we have a cached token + const cacheKey = `${schemeName}_${clientId}`; + const cachedToken = global.__oauthTokenCache[cacheKey]; + const now = Date.now(); + + if (cachedToken && cachedToken.expiresAt > now) { + console.error( + `Using cached OAuth2 token for '${schemeName}' (expires in ${Math.floor((cachedToken.expiresAt - now) / 1000)} seconds)` + ); + return cachedToken.token; + } + + // Determine token URL based on flow type + let tokenUrl = ''; + if (scheme.flows?.clientCredentials?.tokenUrl) { + tokenUrl = scheme.flows.clientCredentials.tokenUrl; + console.error(`Using client credentials flow for '${schemeName}'`); + } else if (scheme.flows?.password?.tokenUrl) { + tokenUrl = scheme.flows.password.tokenUrl; + console.error(`Using password flow for '${schemeName}'`); + } else { + console.error(`No supported OAuth2 flow found for '${schemeName}'`); + return null; + } + + // Prepare the token request + let formData = new URLSearchParams(); + formData.append('grant_type', 'client_credentials'); + + // Add scopes if specified + if (scopes) { + formData.append('scope', scopes); + } + + console.error(`Requesting OAuth2 token from ${tokenUrl}`); + + // Make the token request + const response = await axios({ + method: 'POST', + url: tokenUrl, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`, + }, + data: formData.toString(), + }); + + // Process the response + if (response.data?.access_token) { + const token = response.data.access_token; + const expiresIn = response.data.expires_in || 3600; // Default to 1 hour + + // Cache the token + global.__oauthTokenCache[cacheKey] = { + token, + expiresAt: now + expiresIn * 1000 - 60000, // Expire 1 minute early + }; + + console.error( + `Successfully acquired OAuth2 token for '${schemeName}' (expires in ${expiresIn} seconds)` + ); + return token; + } else { + console.error( + `Failed to acquire OAuth2 token for '${schemeName}': No access_token in response` + ); + return null; + } + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : String(error); + console.error(`Error acquiring OAuth2 token for '${schemeName}':`, errorMessage); + return null; + } +} /** * Executes an API tool with the provided arguments - * + * * @param toolName Name of the tool to execute * @param definition Tool definition * @param toolArgs Arguments provided by the user @@ -419,304 +728,334 @@ async function acquireOAuth2Token(schemeName: string, scheme: any): Promise + toolName: string, + definition: McpToolDefinition, + toolArgs: JsonObject, + allSecuritySchemes: Record ): Promise { try { // Validate arguments against the input schema let validatedArgs: JsonObject; try { - const zodSchema = getZodSchemaFromJsonSchema(definition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); + const zodSchema = getZodSchemaFromJsonSchema(definition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); } catch (error: unknown) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - const errorMessage = error instanceof Error ? error.message : String(error); - return { content: [{ type: 'text', text: `Internal error during validation setup: ${errorMessage}` }] }; - } + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + const errorMessage = error instanceof Error ? error.message : String(error); + return { + content: [ + { type: 'text', text: `Internal error during validation setup: ${errorMessage}` }, + ], + }; + } } // Prepare URL, query parameters, headers, and request body let urlPath = definition.pathTemplate; const queryParams: Record = {}; - const headers: Record = { 'Accept': 'application/json' }; + const headers: Record = { Accept: 'application/json' }; let requestBodyData: any = undefined; // Apply parameters to the URL path, query, or headers definition.executionParameters.forEach((param) => { - const value = validatedArgs[param.name]; - if (typeof value !== 'undefined' && value !== null) { - if (param.in === 'path') { - urlPath = urlPath.replace(`{${param.name}}`, encodeURIComponent(String(value))); - } - else if (param.in === 'query') { - queryParams[param.name] = value; - } - else if (param.in === 'header') { - headers[param.name.toLowerCase()] = String(value); - } + const value = validatedArgs[param.name]; + if (typeof value !== 'undefined' && value !== null) { + if (param.in === 'path') { + urlPath = urlPath.replace(`{${param.name}}`, encodeURIComponent(String(value))); + } else if (param.in === 'query') { + queryParams[param.name] = value; + } else if (param.in === 'header') { + headers[param.name.toLowerCase()] = String(value); } + } }); // Ensure all path parameters are resolved if (urlPath.includes('{')) { - throw new Error(`Failed to resolve path parameters: ${urlPath}`); + throw new Error(`Failed to resolve path parameters: ${urlPath}`); } - + // Construct the full URL const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; // Handle request body if needed if (definition.requestBodyContentType && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - headers['content-type'] = definition.requestBodyContentType; + requestBodyData = validatedArgs['requestBody']; + headers['content-type'] = definition.requestBodyContentType; } - // Apply security requirements if available // Security requirements use OR between array items and AND within each object - const appliedSecurity = definition.securityRequirements?.find(req => { - // Try each security requirement (combined with OR) - return Object.entries(req).every(([schemeName, scopesArray]) => { - const scheme = allSecuritySchemes[schemeName]; - if (!scheme) return false; - - // API Key security (header, query, cookie) - if (scheme.type === 'apiKey') { - return !!process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + const appliedSecurity = definition.securityRequirements?.find((req) => { + // Try each security requirement (combined with OR) + return Object.entries(req).every(([schemeName, scopesArray]) => { + const scheme = allSecuritySchemes[schemeName]; + if (!scheme) return false; + + // API Key security (header, query, cookie) + if (scheme.type === 'apiKey') { + return !!process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + } + + // HTTP security (basic, bearer) + if (scheme.type === 'http') { + if (scheme.scheme?.toLowerCase() === 'bearer') { + return !!process.env[ + `BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + } else if (scheme.scheme?.toLowerCase() === 'basic') { + return ( + !!process.env[ + `BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] && + !!process.env[ + `BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] + ); + } + } + + // OAuth2 security + if (scheme.type === 'oauth2') { + // Check for pre-existing token + if ( + process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`] + ) { + return true; + } + + // Check for client credentials for auto-acquisition + if ( + process.env[ + `OAUTH_CLIENT_ID_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] && + process.env[ + `OAUTH_CLIENT_SECRET_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] + ) { + // Verify we have a supported flow + if (scheme.flows?.clientCredentials || scheme.flows?.password) { + return true; } - - // HTTP security (basic, bearer) - if (scheme.type === 'http') { - if (scheme.scheme?.toLowerCase() === 'bearer') { - return !!process.env[`BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - } - else if (scheme.scheme?.toLowerCase() === 'basic') { - return !!process.env[`BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`] && - !!process.env[`BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - } - } - - // OAuth2 security - if (scheme.type === 'oauth2') { - // Check for pre-existing token - if (process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]) { - return true; - } - - // Check for client credentials for auto-acquisition - if (process.env[`OAUTH_CLIENT_ID_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`] && - process.env[`OAUTH_CLIENT_SECRET_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]) { - // Verify we have a supported flow - if (scheme.flows?.clientCredentials || scheme.flows?.password) { - return true; - } - } - - return false; - } - - // OpenID Connect - if (scheme.type === 'openIdConnect') { - return !!process.env[`OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - } - - return false; - }); + } + + return false; + } + + // OpenID Connect + if (scheme.type === 'openIdConnect') { + return !!process.env[ + `OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + } + + return false; + }); }); // If we found matching security scheme(s), apply them if (appliedSecurity) { - // Apply each security scheme from this requirement (combined with AND) - for (const [schemeName, scopesArray] of Object.entries(appliedSecurity)) { - const scheme = allSecuritySchemes[schemeName]; - - // API Key security - if (scheme?.type === 'apiKey') { - const apiKey = process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (apiKey) { - if (scheme.in === 'header') { - headers[scheme.name.toLowerCase()] = apiKey; - console.error(`Applied API key '${schemeName}' in header '${scheme.name}'`); - } - else if (scheme.in === 'query') { - queryParams[scheme.name] = apiKey; - console.error(`Applied API key '${schemeName}' in query parameter '${scheme.name}'`); - } - else if (scheme.in === 'cookie') { - // Add the cookie, preserving other cookies if they exist - headers['cookie'] = `${scheme.name}=${apiKey}${headers['cookie'] ? `; ${headers['cookie']}` : ''}`; - console.error(`Applied API key '${schemeName}' in cookie '${scheme.name}'`); - } - } - } - // HTTP security (Bearer or Basic) - else if (scheme?.type === 'http') { - if (scheme.scheme?.toLowerCase() === 'bearer') { - const token = process.env[`BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (token) { - headers['authorization'] = `Bearer ${token}`; - console.error(`Applied Bearer token for '${schemeName}'`); - } - } - else if (scheme.scheme?.toLowerCase() === 'basic') { - const username = process.env[`BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - const password = process.env[`BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (username && password) { - headers['authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`; - console.error(`Applied Basic authentication for '${schemeName}'`); - } - } - } - // OAuth2 security - else if (scheme?.type === 'oauth2') { - // First try to use a pre-provided token - let token = process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - - // If no token but we have client credentials, try to acquire a token - if (!token && (scheme.flows?.clientCredentials || scheme.flows?.password)) { - console.error(`Attempting to acquire OAuth token for '${schemeName}'`); - token = (await acquireOAuth2Token(schemeName, scheme)) ?? ''; - } - - // Apply token if available - if (token) { - headers['authorization'] = `Bearer ${token}`; - console.error(`Applied OAuth2 token for '${schemeName}'`); - - // List the scopes that were requested, if any - const scopes = scopesArray as string[]; - if (scopes && scopes.length > 0) { - console.error(`Requested scopes: ${scopes.join(', ')}`); - } - } - } - // OpenID Connect - else if (scheme?.type === 'openIdConnect') { - const token = process.env[`OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (token) { - headers['authorization'] = `Bearer ${token}`; - console.error(`Applied OpenID Connect token for '${schemeName}'`); - - // List the scopes that were requested, if any - const scopes = scopesArray as string[]; - if (scopes && scopes.length > 0) { - console.error(`Requested scopes: ${scopes.join(', ')}`); - } - } + // Apply each security scheme from this requirement (combined with AND) + for (const [schemeName, scopesArray] of Object.entries(appliedSecurity)) { + const scheme = allSecuritySchemes[schemeName]; + + // API Key security + if (scheme?.type === 'apiKey') { + const apiKey = + process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + if (apiKey) { + if (scheme.in === 'header') { + headers[scheme.name.toLowerCase()] = apiKey; + console.error(`Applied API key '${schemeName}' in header '${scheme.name}'`); + } else if (scheme.in === 'query') { + queryParams[scheme.name] = apiKey; + console.error(`Applied API key '${schemeName}' in query parameter '${scheme.name}'`); + } else if (scheme.in === 'cookie') { + // Add the cookie, preserving other cookies if they exist + headers['cookie'] = + `${scheme.name}=${apiKey}${headers['cookie'] ? `; ${headers['cookie']}` : ''}`; + console.error(`Applied API key '${schemeName}' in cookie '${scheme.name}'`); } + } } - } + // HTTP security (Bearer or Basic) + else if (scheme?.type === 'http') { + if (scheme.scheme?.toLowerCase() === 'bearer') { + const token = + process.env[`BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + if (token) { + headers['authorization'] = `Bearer ${token}`; + console.error(`Applied Bearer token for '${schemeName}'`); + } + } else if (scheme.scheme?.toLowerCase() === 'basic') { + const username = + process.env[ + `BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + const password = + process.env[ + `BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + if (username && password) { + headers['authorization'] = + `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`; + console.error(`Applied Basic authentication for '${schemeName}'`); + } + } + } + // OAuth2 security + else if (scheme?.type === 'oauth2') { + // First try to use a pre-provided token + let token = + process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + + // If no token but we have client credentials, try to acquire a token + if (!token && (scheme.flows?.clientCredentials || scheme.flows?.password)) { + console.error(`Attempting to acquire OAuth token for '${schemeName}'`); + token = (await acquireOAuth2Token(schemeName, scheme)) ?? ''; + } + + // Apply token if available + if (token) { + headers['authorization'] = `Bearer ${token}`; + console.error(`Applied OAuth2 token for '${schemeName}'`); + + // List the scopes that were requested, if any + const scopes = scopesArray as string[]; + if (scopes && scopes.length > 0) { + console.error(`Requested scopes: ${scopes.join(', ')}`); + } + } + } + // OpenID Connect + else if (scheme?.type === 'openIdConnect') { + const token = + process.env[`OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + if (token) { + headers['authorization'] = `Bearer ${token}`; + console.error(`Applied OpenID Connect token for '${schemeName}'`); + + // List the scopes that were requested, if any + const scopes = scopesArray as string[]; + if (scopes && scopes.length > 0) { + console.error(`Requested scopes: ${scopes.join(', ')}`); + } + } + } + } + } // Log warning if security is required but not available else if (definition.securityRequirements?.length > 0) { - // First generate a more readable representation of the security requirements - const securityRequirementsString = definition.securityRequirements - .map(req => { - const parts = Object.entries(req) - .map(([name, scopesArray]) => { - const scopes = scopesArray as string[]; - if (scopes.length === 0) return name; - return `${name} (scopes: ${scopes.join(', ')})`; - }) - .join(' AND '); - return `[${parts}]`; + // First generate a more readable representation of the security requirements + const securityRequirementsString = definition.securityRequirements + .map((req) => { + const parts = Object.entries(req) + .map(([name, scopesArray]) => { + const scopes = scopesArray as string[]; + if (scopes.length === 0) return name; + return `${name} (scopes: ${scopes.join(', ')})`; }) - .join(' OR '); - - console.warn(`Tool '${toolName}' requires security: ${securityRequirementsString}, but no suitable credentials found.`); + .join(' AND '); + return `[${parts}]`; + }) + .join(' OR '); + + console.warn( + `Tool '${toolName}' requires security: ${securityRequirementsString}, but no suitable credentials found.` + ); } - // Prepare the axios request configuration const config: AxiosRequestConfig = { - method: definition.method.toUpperCase(), - url: requestUrl, - params: queryParams, + method: definition.method.toUpperCase(), + url: requestUrl, + params: queryParams, headers: headers, ...(requestBodyData !== undefined && { data: requestBodyData }), }; // Log request info to stderr (doesn't affect MCP output) console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - + // Execute the request const response = await axios(config); // Process and format the response let responseText = ''; const contentType = response.headers['content-type']?.toLowerCase() || ''; - + // Handle JSON responses - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { - responseText = JSON.stringify(response.data, null, 2); - } catch (e) { - responseText = "[Stringify Error]"; - } - } + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Stringify Error]'; + } + } // Handle string responses - else if (typeof response.data === 'string') { - responseText = response.data; + else if (typeof response.data === 'string') { + responseText = response.data; } // Handle other response types - else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); + else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); } // Handle empty responses - else { - responseText = `(Status: ${response.status} - No body content)`; + else { + responseText = `(Status: ${response.status} - No body content)`; } - - // Return formatted response - return { - content: [ - { - type: "text", - text: `API Response (Status: ${response.status}):\n${responseText}` - } - ], - }; + // Return formatted response + return { + content: [ + { + type: 'text', + text: `API Response (Status: ${response.status}):\n${responseText}`, + }, + ], + }; } catch (error: unknown) { // Handle errors during execution let errorMessage: string; - + // Format Axios errors specially - if (axios.isAxiosError(error)) { - errorMessage = formatApiError(error); + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); } // Handle standard errors - else if (error instanceof Error) { - errorMessage = error.message; + else if (error instanceof Error) { + errorMessage = error.message; } // Handle unexpected error types - else { - errorMessage = 'Unexpected error: ' + String(error); + else { + errorMessage = 'Unexpected error: ' + String(error); } - + // Log error to stderr console.error(`Error during execution of tool '${toolName}':`, errorMessage); - + // Return error message to client - return { content: [{ type: "text", text: errorMessage }] }; + return { content: [{ type: 'text', text: errorMessage }] }; } } - /** * Main function to start the server */ async function main() { -// Set up Web Server transport + // Set up Web Server transport try { await setupWebServer(server, 3000); } catch (error) { - console.error("Error setting up web server:", error); + console.error('Error setting up web server:', error); process.exit(1); } } @@ -725,8 +1064,8 @@ async function main() { * Cleanup function for graceful shutdown */ async function cleanup() { - console.error("Shutting down MCP server..."); - process.exit(0); + console.error('Shutting down MCP server...'); + process.exit(0); } // Register signal handlers @@ -735,65 +1074,63 @@ process.on('SIGTERM', cleanup); // Start the server main().catch((error) => { - console.error("Fatal error in main execution:", error); + console.error('Fatal error in main execution:', error); process.exit(1); }); /** * Formats API errors for better readability - * + * * @param error Axios error * @returns Formatted error message */ function formatApiError(error: AxiosError): string { - let message = 'API request failed.'; - if (error.response) { - message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `; - const responseData = error.response.data; - const MAX_LEN = 200; - if (typeof responseData === 'string') { - message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`; - } - else if (responseData) { - try { - const jsonString = JSON.stringify(responseData); - message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`; - } catch { - message += 'Response: [Could not serialize data]'; - } - } - else { - message += 'No response body received.'; - } - } else if (error.request) { - message = 'API Network Error: No response received from server.'; - if (error.code) message += ` (Code: ${error.code})`; - } else { - message += `API Request Setup Error: ${error.message}`; + let message = 'API request failed.'; + if (error.response) { + message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `; + const responseData = error.response.data; + const MAX_LEN = 200; + if (typeof responseData === 'string') { + message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`; + } else if (responseData) { + try { + const jsonString = JSON.stringify(responseData); + message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`; + } catch { + message += 'Response: [Could not serialize data]'; + } + } else { + message += 'No response body received.'; } - return message; + } else if (error.request) { + message = 'API Network Error: No response received from server.'; + if (error.code) message += ` (Code: ${error.code})`; + } else { + message += `API Request Setup Error: ${error.message}`; + } + return message; } /** * Converts a JSON Schema to a Zod schema for runtime validation - * + * * @param jsonSchema JSON Schema * @param toolName Tool name for error reporting * @returns Zod schema */ function getZodSchemaFromJsonSchema(jsonSchema: any, toolName: string): z.ZodTypeAny { - if (typeof jsonSchema !== 'object' || jsonSchema === null) { - return z.object({}).passthrough(); - } - try { - const zodSchemaString = jsonSchemaToZod(jsonSchema); - const zodSchema = eval(zodSchemaString); - if (typeof zodSchema?.parse !== 'function') { - throw new Error('Eval did not produce a valid Zod schema.'); - } - return zodSchema as z.ZodTypeAny; - } catch (err: any) { - console.error(`Failed to generate/evaluate Zod schema for '${toolName}':`, err); - return z.object({}).passthrough(); + if (typeof jsonSchema !== 'object' || jsonSchema === null) { + return z.object({}).passthrough(); + } + try { + const zodSchemaString = jsonSchemaToZod(jsonSchema); + const zodSchema = eval(zodSchemaString); + if (typeof zodSchema?.parse !== 'function') { + throw new Error('Eval did not produce a valid Zod schema.'); } + return zodSchema as z.ZodTypeAny; + } catch (err: any) { + console.error(`Failed to generate/evaluate Zod schema for '${toolName}':`, err); + return z.object({}).passthrough(); + } } diff --git a/examples/pet-store-sse/src/web-server.ts b/examples/pet-store-sse/src/web-server.ts index 36461c5..c44041b 100644 --- a/examples/pet-store-sse/src/web-server.ts +++ b/examples/pet-store-sse/src/web-server.ts @@ -1,286 +1,304 @@ - /** -* Web server setup for HTTP-based MCP communication using Hono -*/ + * Web server setup for HTTP-based MCP communication using Hono + */ import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { serve } from '@hono/node-server'; import { streamSSE } from 'hono/streaming'; import { v4 as uuid } from 'uuid'; -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { JSONRPCMessage, JSONRPCMessageSchema } from "@modelcontextprotocol/sdk/types.js"; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { JSONRPCMessage, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js'; import type { Context } from 'hono'; import type { SSEStreamingApi } from 'hono/streaming'; -import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; +import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; // Import server configuration constants import { SERVER_NAME, SERVER_VERSION } from './index.js'; /** -* Custom SSE Transport implementation using Hono's streaming API -*/ + * Custom SSE Transport implementation using Hono's streaming API + */ class SSETransport implements Transport { -private _sessionId: string; -private stream: SSEStreamingApi; -private messageUrl: string; + private _sessionId: string; + private stream: SSEStreamingApi; + private messageUrl: string; -onclose?: () => void; -onerror?: (error: Error) => void; -onmessage?: (message: JSONRPCMessage) => void; + onclose?: () => void; + onerror?: (error: Error) => void; + onmessage?: (message: JSONRPCMessage) => void; -constructor(messageUrl: string, stream: SSEStreamingApi) { - this._sessionId = uuid(); - this.stream = stream; - this.messageUrl = messageUrl; - - // Set up stream abort handler - this.stream.onAbort(() => { - console.error(`SSE connection aborted for session ${this._sessionId}`); - this.close(); - }); -} + constructor(messageUrl: string, stream: SSEStreamingApi) { + this._sessionId = uuid(); + this.stream = stream; + this.messageUrl = messageUrl; -get sessionId(): string { - return this._sessionId; -} - -async start(): Promise { - if (this.stream.closed) { - throw new Error('SSE transport already closed!'); + // Set up stream abort handler + this.stream.onAbort(() => { + console.error(`SSE connection aborted for session ${this._sessionId}`); + this.close(); + }); } - - // Send the endpoint information - await this.stream.writeSSE({ - event: 'endpoint', - data: `${this.messageUrl}?sessionId=${this._sessionId}` - }); - - // Send session ID and connection info in a format the client can understand - await this.stream.writeSSE({ - event: 'session', - data: JSON.stringify({ - type: 'session_id', - session_id: this._sessionId - }) - }); - - // Send a welcome notification - await this.send({ - jsonrpc: "2.0", - method: "notification", - params: { - type: "welcome", - clientInfo: { - sessionId: this._sessionId, - serverName: SERVER_NAME, - serverVersion: SERVER_VERSION - } + + get sessionId(): string { + return this._sessionId; + } + + async start(): Promise { + if (this.stream.closed) { + throw new Error('SSE transport already closed!'); } - }); -} -async handlePostMessage(c: Context): Promise { - if (this.stream?.closed) { - return c.text('SSE connection closed', 400); + // Send the endpoint information + await this.stream.writeSSE({ + event: 'endpoint', + data: `${this.messageUrl}?sessionId=${this._sessionId}`, + }); + + // Send session ID and connection info in a format the client can understand + await this.stream.writeSSE({ + event: 'session', + data: JSON.stringify({ + type: 'session_id', + session_id: this._sessionId, + }), + }); + + // Send a welcome notification + await this.send({ + jsonrpc: '2.0', + method: 'notification', + params: { + type: 'welcome', + clientInfo: { + sessionId: this._sessionId, + serverName: SERVER_NAME, + serverVersion: SERVER_VERSION, + }, + }, + }); } - - try { - // Parse and validate the message - const body = await c.req.json(); - + + async handlePostMessage(c: Context): Promise { + if (this.stream?.closed) { + return c.text('SSE connection closed', 400); + } + try { // Parse and validate the message - const parsedMessage = JSONRPCMessageSchema.parse(body); - - // Forward to the message handler - if (this.onmessage) { - this.onmessage(parsedMessage); - return c.text('Accepted', 202); - } else { - return c.text('No message handler defined', 500); + const body = await c.req.json(); + + try { + // Parse and validate the message + const parsedMessage = JSONRPCMessageSchema.parse(body); + + // Forward to the message handler + if (this.onmessage) { + this.onmessage(parsedMessage); + return c.text('Accepted', 202); + } else { + return c.text('No message handler defined', 500); + } + } catch (error) { + if (this.onerror) { + this.onerror(error instanceof Error ? error : new Error(String(error))); + } + console.error('Error parsing message:', error); + return c.text('Invalid message format', 400); } } catch (error) { if (this.onerror) { this.onerror(error instanceof Error ? error : new Error(String(error))); } - console.error('Error parsing message:', error); - return c.text('Invalid message format', 400); + console.error('Error processing request:', error); + return c.text('Error processing message', 400); } - } catch (error) { - if (this.onerror) { - this.onerror(error instanceof Error ? error : new Error(String(error))); + } + + async close(): Promise { + if (this.stream && !this.stream.closed) { + this.stream.abort(); } - console.error('Error processing request:', error); - return c.text('Error processing message', 400); - } -} -async close(): Promise { - if (this.stream && !this.stream.closed) { - this.stream.abort(); + if (this.onclose) { + this.onclose(); + } } - - if (this.onclose) { - this.onclose(); - } -} -async send(message: JSONRPCMessage): Promise { - if (this.stream.closed) { - throw new Error('Not connected'); + async send(message: JSONRPCMessage): Promise { + if (this.stream.closed) { + throw new Error('Not connected'); + } + + await this.stream.writeSSE({ + event: 'message', + data: JSON.stringify(message), + }); } - - await this.stream.writeSSE({ - event: 'message', - data: JSON.stringify(message) - }); -} } /** -* Sets up a web server for the MCP server using Server-Sent Events (SSE) -* -* @param server The MCP Server instance -* @param port The port to listen on (default: 3000) -* @returns The Hono app instance -*/ + * Sets up a web server for the MCP server using Server-Sent Events (SSE) + * + * @param server The MCP Server instance + * @param port The port to listen on (default: 3000) + * @returns The Hono app instance + */ export async function setupWebServer(server: Server, port = 3000) { -// Create Hono app -const app = new Hono(); + // Create Hono app + const app = new Hono(); -// Enable CORS -app.use('*', cors()); + // Enable CORS + app.use('*', cors()); -// Store active SSE transports by session ID -const transports: {[sessionId: string]: SSETransport} = {}; + // Store active SSE transports by session ID + const transports: { [sessionId: string]: SSETransport } = {}; -// Add a simple health check endpoint -app.get('/health', (c) => { - return c.json({ status: 'OK', server: SERVER_NAME, version: SERVER_VERSION }); -}); - -// SSE endpoint for clients to connect to -app.get("/sse", (c) => { - return streamSSE(c, async (stream) => { - // Create SSE transport - const transport = new SSETransport('/api/messages', stream); - const sessionId = transport.sessionId; - - console.error(`New SSE connection established: ${sessionId}`); - - // Store the transport - transports[sessionId] = transport; - - // Set up cleanup on transport close - transport.onclose = () => { - console.error(`SSE connection closed for session ${sessionId}`); - delete transports[sessionId]; - }; - - // Make the transport available to the MCP server - try { - transport.onmessage = async (message: JSONRPCMessage) => { - try { - // The server will automatically send a response via the transport - // if the message has an ID (i.e., it's a request, not a notification) - } catch (error) { - console.error('Error handling MCP message:', error); - } - }; - - // Connect to the MCP server - await server.connect(transport); - } catch (error) { - console.error(`Error connecting transport for session ${sessionId}:`, error); - } - - // Keep the stream open until aborted - while (!stream.closed) { - await stream.sleep(1000); - } + // Add a simple health check endpoint + app.get('/health', (c) => { + return c.json({ status: 'OK', server: SERVER_NAME, version: SERVER_VERSION }); }); -}); -// API endpoint for clients to send messages -app.post("/api/messages", async (c) => { - const sessionId = c.req.query('sessionId'); - - if (!sessionId) { - return c.json({ error: 'Missing sessionId query parameter' }, 400); - } - - const transport = transports[sessionId]; - - if (!transport) { - return c.json({ error: 'No active session found with the provided sessionId' }, 404); - } - - return transport.handlePostMessage(c); -}); + // SSE endpoint for clients to connect to + app.get('/sse', (c) => { + return streamSSE(c, async (stream) => { + // Create SSE transport + const transport = new SSETransport('/api/messages', stream); + const sessionId = transport.sessionId; -// Static files for the web client (if any) -app.get('/*', async (c) => { - const filePath = c.req.path === '/' ? '/index.html' : c.req.path; - try { - // Use Node.js fs to serve static files - const fs = await import('fs'); - const path = await import('path'); - const { fileURLToPath } = await import('url'); - - const __dirname = path.dirname(fileURLToPath(import.meta.url)); - const publicPath = path.join(__dirname, '..', '..', 'public'); - const fullPath = path.join(publicPath, filePath); - - // Simple security check to prevent directory traversal - if (!fullPath.startsWith(publicPath)) { - return c.text('Forbidden', 403); + console.error(`New SSE connection established: ${sessionId}`); + + // Store the transport + transports[sessionId] = transport; + + // Set up cleanup on transport close + transport.onclose = () => { + console.error(`SSE connection closed for session ${sessionId}`); + delete transports[sessionId]; + }; + + // Make the transport available to the MCP server + try { + transport.onmessage = async (message: JSONRPCMessage) => { + try { + // The server will automatically send a response via the transport + // if the message has an ID (i.e., it's a request, not a notification) + } catch (error) { + console.error('Error handling MCP message:', error); + } + }; + + // Connect to the MCP server + await server.connect(transport); + } catch (error) { + console.error(`Error connecting transport for session ${sessionId}:`, error); + } + + // Keep the stream open until aborted + while (!stream.closed) { + await stream.sleep(1000); + } + }); + }); + + // API endpoint for clients to send messages + app.post('/api/messages', async (c) => { + const sessionId = c.req.query('sessionId'); + + if (!sessionId) { + return c.json({ error: 'Missing sessionId query parameter' }, 400); } - + + const transport = transports[sessionId]; + + if (!transport) { + return c.json({ error: 'No active session found with the provided sessionId' }, 404); + } + + return transport.handlePostMessage(c); + }); + + // Static files for the web client (if any) + app.get('/*', async (c) => { + const filePath = c.req.path === '/' ? '/index.html' : c.req.path; try { - const stat = fs.statSync(fullPath); - if (stat.isFile()) { - const content = fs.readFileSync(fullPath); - - // Set content type based on file extension - const ext = path.extname(fullPath).toLowerCase(); - let contentType = 'text/plain'; - - switch (ext) { - case '.html': contentType = 'text/html'; break; - case '.css': contentType = 'text/css'; break; - case '.js': contentType = 'text/javascript'; break; - case '.json': contentType = 'application/json'; break; - case '.png': contentType = 'image/png'; break; - case '.jpg': contentType = 'image/jpeg'; break; - case '.svg': contentType = 'image/svg+xml'; break; + // Use Node.js fs to serve static files + const fs = await import('fs'); + const path = await import('path'); + const { fileURLToPath } = await import('url'); + + const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const publicPath = path.join(__dirname, '..', '..', 'public'); + const fullPath = path.join(publicPath, filePath); + + // Simple security check to prevent directory traversal + if (!fullPath.startsWith(publicPath)) { + return c.text('Forbidden', 403); + } + + try { + const stat = fs.statSync(fullPath); + if (stat.isFile()) { + const content = fs.readFileSync(fullPath); + + // Set content type based on file extension + const ext = path.extname(fullPath).toLowerCase(); + let contentType = 'text/plain'; + + switch (ext) { + case '.html': + contentType = 'text/html'; + break; + case '.css': + contentType = 'text/css'; + break; + case '.js': + contentType = 'text/javascript'; + break; + case '.json': + contentType = 'application/json'; + break; + case '.png': + contentType = 'image/png'; + break; + case '.jpg': + contentType = 'image/jpeg'; + break; + case '.svg': + contentType = 'image/svg+xml'; + break; + } + + return new Response(content, { + headers: { 'Content-Type': contentType }, + }); } - - return new Response(content, { - headers: { 'Content-Type': contentType } - }); + } catch (err) { + // File not found or other error + return c.text('Not Found', 404); } } catch (err) { - // File not found or other error - return c.text('Not Found', 404); + console.error('Error serving static file:', err); + return c.text('Internal Server Error', 500); } - } catch (err) { - console.error('Error serving static file:', err); - return c.text('Internal Server Error', 500); - } - - return c.text('Not Found', 404); -}); -// Start the server -serve({ - fetch: app.fetch, - port -}, (info) => { - console.error(`MCP Web Server running at http://localhost:${info.port}`); - console.error(`- SSE Endpoint: http://localhost:${info.port}/sse`); - console.error(`- Messages Endpoint: http://localhost:${info.port}/api/messages?sessionId=YOUR_SESSION_ID`); - console.error(`- Health Check: http://localhost:${info.port}/health`); -}); + return c.text('Not Found', 404); + }); -return app; + // Start the server + serve( + { + fetch: app.fetch, + port, + }, + (info) => { + console.error(`MCP Web Server running at http://localhost:${info.port}`); + console.error(`- SSE Endpoint: http://localhost:${info.port}/sse`); + console.error( + `- Messages Endpoint: http://localhost:${info.port}/api/messages?sessionId=YOUR_SESSION_ID` + ); + console.error(`- Health Check: http://localhost:${info.port}/health`); + } + ); + + return app; } diff --git a/examples/pet-store-sse/tsconfig.json b/examples/pet-store-sse/tsconfig.json index ed2966d..13e80dc 100644 --- a/examples/pet-store-sse/tsconfig.json +++ b/examples/pet-store-sse/tsconfig.json @@ -17,12 +17,6 @@ "sourceMap": true, "forceConsistentCasingInFileNames": true }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "build", - "**/*.test.ts" - ] -} \ No newline at end of file + "include": ["src/**/*"], + "exclude": ["node_modules", "build", "**/*.test.ts"] +} diff --git a/examples/pet-store-streamable-http/.eslintrc.json b/examples/pet-store-streamable-http/.eslintrc.json index 8cb5c8e..2c368f9 100644 --- a/examples/pet-store-streamable-http/.eslintrc.json +++ b/examples/pet-store-streamable-http/.eslintrc.json @@ -1,12 +1,7 @@ { "parser": "@typescript-eslint/parser", - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "plugins": [ - "@typescript-eslint" - ], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "plugins": ["@typescript-eslint"], "env": { "node": true, "es2022": true @@ -15,10 +10,7 @@ "no-console": [ "error", { - "allow": [ - "error", - "warn" - ] + "allow": ["error", "warn"] } ], "@typescript-eslint/explicit-function-return-type": "off", @@ -30,4 +22,4 @@ } ] } -} \ No newline at end of file +} diff --git a/examples/pet-store-streamable-http/.prettierrc b/examples/pet-store-streamable-http/.prettierrc index 494b947..3de448e 100644 --- a/examples/pet-store-streamable-http/.prettierrc +++ b/examples/pet-store-streamable-http/.prettierrc @@ -4,4 +4,4 @@ "singleQuote": true, "printWidth": 100, "tabWidth": 2 -} \ No newline at end of file +} diff --git a/examples/pet-store-streamable-http/docs/oauth2-configuration.md b/examples/pet-store-streamable-http/docs/oauth2-configuration.md index 9f3625b..1a5a040 100644 --- a/examples/pet-store-streamable-http/docs/oauth2-configuration.md +++ b/examples/pet-store-streamable-http/docs/oauth2-configuration.md @@ -13,11 +13,13 @@ This API uses OAuth2 for authentication. The MCP server can handle OAuth2 authen - `OAUTH_CLIENT_ID_PETSTORE_AUTH`: Your OAuth client ID - `OAUTH_CLIENT_SECRET_PETSTORE_AUTH`: Your OAuth client secret + ## Token Caching The MCP server automatically caches OAuth tokens obtained via client credentials flow. Tokens are cached for their lifetime (as specified by the `expires_in` parameter in the token response) minus 60 seconds as a safety margin. When making API requests, the server will: + 1. Check for a cached token that's still valid 2. Use the cached token if available 3. Request a new token if no valid cached token exists diff --git a/examples/pet-store-streamable-http/public/index.html b/examples/pet-store-streamable-http/public/index.html index ebc29a0..6e000c9 100644 --- a/examples/pet-store-streamable-http/public/index.html +++ b/examples/pet-store-streamable-http/public/index.html @@ -1,402 +1,424 @@ - + - - - - swagger-petstore---openapi-3-0 MCP StreamableHTTP Test Client - - - -

swagger-petstore---openapi-3-0 MCP StreamableHTTP Test Client

-

Disconnected

- -
-
- -
- - -
-
- - - -
-
-

Debug Console

- -
-
-
- - - - \ No newline at end of file + + // Event listeners + sendButton.addEventListener('click', sendMessage); + userInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') sendMessage(); + }); + + // Initialize on page load + appendMessage('system', 'Initializing MCP connection...'); + initialize(); + + + diff --git a/examples/pet-store-streamable-http/src/index.ts b/examples/pet-store-streamable-http/src/index.ts index 0d92628..64e77b7 100644 --- a/examples/pet-store-streamable-http/src/index.ts +++ b/examples/pet-store-streamable-http/src/index.ts @@ -8,16 +8,16 @@ import dotenv from 'dotenv'; dotenv.config(); -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, type Tool, type CallToolResult, - type CallToolRequest -} from "@modelcontextprotocol/sdk/types.js"; -import { setupStreamableHttpServer } from "./streamable-http.js"; + type CallToolRequest, +} from '@modelcontextprotocol/sdk/types.js'; +import { setupStreamableHttpServer } from './streamable-http.js'; import { z, ZodError } from 'zod'; import { jsonSchemaToZod } from 'json-schema-to-zod'; @@ -32,386 +32,695 @@ type JsonObject = Record; * Interface for MCP Tool Definition */ interface McpToolDefinition { - name: string; - description: string; - inputSchema: any; - method: string; - pathTemplate: string; - executionParameters: { name: string, in: string }[]; - requestBodyContentType?: string; - securityRequirements: any[]; + name: string; + description: string; + inputSchema: any; + method: string; + pathTemplate: string; + executionParameters: { name: string; in: string }[]; + requestBodyContentType?: string; + securityRequirements: any[]; } /** * Server configuration */ -export const SERVER_NAME = "swagger-petstore---openapi-3-0"; -export const SERVER_VERSION = "1.0.26"; -export const API_BASE_URL = "https://petstore3.swagger.io/api/v3"; +export const SERVER_NAME = 'swagger-petstore---openapi-3-0'; +export const SERVER_VERSION = '1.0.26'; +export const API_BASE_URL = 'https://petstore3.swagger.io/api/v3'; /** * MCP Server instance */ const server = new Server( - { name: SERVER_NAME, version: SERVER_VERSION }, - { capabilities: { tools: {} } } + { name: SERVER_NAME, version: SERVER_VERSION }, + { capabilities: { tools: {} } } ); /** * Map of tool definitions by name */ const toolDefinitionMap: Map = new Map([ - - ["updatepet", { - name: "updatepet", - description: `Update an existing pet by Id.`, - inputSchema: {"type":"object","properties":{"requestBody":{"required":["name","photoUrls"],"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"},"category":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}},"photoUrls":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"description":"Update an existent pet in the store"}},"required":["requestBody"]}, - method: "put", - pathTemplate: "/pet", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["addpet", { - name: "addpet", - description: `Add a new pet to the store.`, - inputSchema: {"type":"object","properties":{"requestBody":{"required":["name","photoUrls"],"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"},"category":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}},"photoUrls":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"name":{"type":"string"}}}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"description":"Create a new pet in the store"}},"required":["requestBody"]}, - method: "post", - pathTemplate: "/pet", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["findpetsbystatus", { - name: "findpetsbystatus", - description: `Multiple status values can be provided with comma separated strings.`, - inputSchema: {"type":"object","properties":{"status":{"type":"string","default":"available","enum":["available","pending","sold"],"description":"Status values that need to be considered for filter"}}}, - method: "get", - pathTemplate: "/pet/findByStatus", - executionParameters: [{"name":"status","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["findpetsbytags", { - name: "findpetsbytags", - description: `Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.`, - inputSchema: {"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"},"description":"Tags to filter by"}}}, - method: "get", - pathTemplate: "/pet/findByTags", - executionParameters: [{"name":"tags","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["getpetbyid", { - name: "getpetbyid", - description: `Returns a single pet.`, - inputSchema: {"type":"object","properties":{"petId":{"type":"number","format":"int64","description":"ID of pet to return"}},"required":["petId"]}, - method: "get", - pathTemplate: "/pet/{petId}", - executionParameters: [{"name":"petId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [{"api_key":[]},{"petstore_auth":["write:pets","read:pets"]}] - }], - ["updatepetwithform", { - name: "updatepetwithform", - description: `Updates a pet resource based on the form data.`, - inputSchema: {"type":"object","properties":{"petId":{"type":"number","format":"int64","description":"ID of pet that needs to be updated"},"name":{"type":"string","description":"Name of pet that needs to be updated"},"status":{"type":"string","description":"Status of pet that needs to be updated"}},"required":["petId"]}, - method: "post", - pathTemplate: "/pet/{petId}", - executionParameters: [{"name":"petId","in":"path"},{"name":"name","in":"query"},{"name":"status","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["deletepet", { - name: "deletepet", - description: `Delete a pet.`, - inputSchema: {"type":"object","properties":{"api_key":{"type":"string"},"petId":{"type":"number","format":"int64","description":"Pet id to delete"}},"required":["petId"]}, - method: "delete", - pathTemplate: "/pet/{petId}", - executionParameters: [{"name":"api_key","in":"header"},{"name":"petId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["uploadfile", { - name: "uploadfile", - description: `Upload image of the pet.`, - inputSchema: {"type":"object","properties":{"petId":{"type":"number","format":"int64","description":"ID of pet to update"},"additionalMetadata":{"type":"string","description":"Additional Metadata"},"requestBody":{"type":"string","description":"Request body (content type: application/octet-stream)"}},"required":["petId"]}, - method: "post", - pathTemplate: "/pet/{petId}/uploadImage", - executionParameters: [{"name":"petId","in":"path"},{"name":"additionalMetadata","in":"query"}], - requestBodyContentType: "application/octet-stream", - securityRequirements: [{"petstore_auth":["write:pets","read:pets"]}] - }], - ["getinventory", { - name: "getinventory", - description: `Returns a map of status codes to quantities.`, - inputSchema: {"type":"object","properties":{}}, - method: "get", - pathTemplate: "/store/inventory", - executionParameters: [], - requestBodyContentType: undefined, - securityRequirements: [{"api_key":[]}] - }], - ["placeorder", { - name: "placeorder", - description: `Place a new order in the store.`, - inputSchema: {"type":"object","properties":{"requestBody":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"petId":{"type":"number","format":"int64"},"quantity":{"type":"number","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean"}},"description":"The JSON request body."}}}, - method: "post", - pathTemplate: "/store/order", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["getorderbyid", { - name: "getorderbyid", - description: `For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.`, - inputSchema: {"type":"object","properties":{"orderId":{"type":"number","format":"int64","description":"ID of order that needs to be fetched"}},"required":["orderId"]}, - method: "get", - pathTemplate: "/store/order/{orderId}", - executionParameters: [{"name":"orderId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["deleteorder", { - name: "deleteorder", - description: `For valid response try integer IDs with value < 1000. Anything above 1000 or non-integers will generate API errors.`, - inputSchema: {"type":"object","properties":{"orderId":{"type":"number","format":"int64","description":"ID of the order that needs to be deleted"}},"required":["orderId"]}, - method: "delete", - pathTemplate: "/store/order/{orderId}", - executionParameters: [{"name":"orderId","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["createuser", { - name: "createuser", - description: `This can only be done by the logged in user.`, - inputSchema: {"type":"object","properties":{"requestBody":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"number","description":"User Status","format":"int32"}},"description":"Created user object"}}}, - method: "post", - pathTemplate: "/user", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["createuserswithlistinput", { - name: "createuserswithlistinput", - description: `Creates list of users with given input array.`, - inputSchema: {"type":"object","properties":{"requestBody":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"number","description":"User Status","format":"int32"}}},"description":"The JSON request body."}}}, - method: "post", - pathTemplate: "/user/createWithList", - executionParameters: [], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["loginuser", { - name: "loginuser", - description: `Log into the system.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"The user name for login"},"password":{"type":"string","description":"The password for login in clear text"}}}, - method: "get", - pathTemplate: "/user/login", - executionParameters: [{"name":"username","in":"query"},{"name":"password","in":"query"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["logoutuser", { - name: "logoutuser", - description: `Log user out of the system.`, - inputSchema: {"type":"object","properties":{}}, - method: "get", - pathTemplate: "/user/logout", - executionParameters: [], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["getuserbyname", { - name: "getuserbyname", - description: `Get user detail based on username.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"The name that needs to be fetched. Use user1 for testing"}},"required":["username"]}, - method: "get", - pathTemplate: "/user/{username}", - executionParameters: [{"name":"username","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], - ["updateuser", { - name: "updateuser", - description: `This can only be done by the logged in user.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"name that need to be deleted"},"requestBody":{"type":"object","properties":{"id":{"type":"number","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"number","description":"User Status","format":"int32"}},"description":"Update an existent user in the store"}},"required":["username"]}, - method: "put", - pathTemplate: "/user/{username}", - executionParameters: [{"name":"username","in":"path"}], - requestBodyContentType: "application/json", - securityRequirements: [] - }], - ["deleteuser", { - name: "deleteuser", - description: `This can only be done by the logged in user.`, - inputSchema: {"type":"object","properties":{"username":{"type":"string","description":"The name that needs to be deleted"}},"required":["username"]}, - method: "delete", - pathTemplate: "/user/{username}", - executionParameters: [{"name":"username","in":"path"}], - requestBodyContentType: undefined, - securityRequirements: [] - }], + [ + 'updatepet', + { + name: 'updatepet', + description: `Update an existing pet by Id.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + required: ['name', 'photoUrls'], + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + name: { type: 'string' }, + category: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + photoUrls: { type: 'array', items: { type: 'string' } }, + tags: { + type: 'array', + items: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + }, + status: { + type: 'string', + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + }, + }, + description: 'Update an existent pet in the store', + }, + }, + required: ['requestBody'], + }, + method: 'put', + pathTemplate: '/pet', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'addpet', + { + name: 'addpet', + description: `Add a new pet to the store.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + required: ['name', 'photoUrls'], + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + name: { type: 'string' }, + category: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + photoUrls: { type: 'array', items: { type: 'string' } }, + tags: { + type: 'array', + items: { + type: 'object', + properties: { id: { type: 'number', format: 'int64' }, name: { type: 'string' } }, + }, + }, + status: { + type: 'string', + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + }, + }, + description: 'Create a new pet in the store', + }, + }, + required: ['requestBody'], + }, + method: 'post', + pathTemplate: '/pet', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'findpetsbystatus', + { + name: 'findpetsbystatus', + description: `Multiple status values can be provided with comma separated strings.`, + inputSchema: { + type: 'object', + properties: { + status: { + type: 'string', + default: 'available', + enum: ['available', 'pending', 'sold'], + description: 'Status values that need to be considered for filter', + }, + }, + }, + method: 'get', + pathTemplate: '/pet/findByStatus', + executionParameters: [{ name: 'status', in: 'query' }], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'findpetsbytags', + { + name: 'findpetsbytags', + description: `Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.`, + inputSchema: { + type: 'object', + properties: { + tags: { type: 'array', items: { type: 'string' }, description: 'Tags to filter by' }, + }, + }, + method: 'get', + pathTemplate: '/pet/findByTags', + executionParameters: [{ name: 'tags', in: 'query' }], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'getpetbyid', + { + name: 'getpetbyid', + description: `Returns a single pet.`, + inputSchema: { + type: 'object', + properties: { + petId: { type: 'number', format: 'int64', description: 'ID of pet to return' }, + }, + required: ['petId'], + }, + method: 'get', + pathTemplate: '/pet/{petId}', + executionParameters: [{ name: 'petId', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [{ api_key: [] }, { petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'updatepetwithform', + { + name: 'updatepetwithform', + description: `Updates a pet resource based on the form data.`, + inputSchema: { + type: 'object', + properties: { + petId: { + type: 'number', + format: 'int64', + description: 'ID of pet that needs to be updated', + }, + name: { type: 'string', description: 'Name of pet that needs to be updated' }, + status: { type: 'string', description: 'Status of pet that needs to be updated' }, + }, + required: ['petId'], + }, + method: 'post', + pathTemplate: '/pet/{petId}', + executionParameters: [ + { name: 'petId', in: 'path' }, + { name: 'name', in: 'query' }, + { name: 'status', in: 'query' }, + ], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'deletepet', + { + name: 'deletepet', + description: `Delete a pet.`, + inputSchema: { + type: 'object', + properties: { + api_key: { type: 'string' }, + petId: { type: 'number', format: 'int64', description: 'Pet id to delete' }, + }, + required: ['petId'], + }, + method: 'delete', + pathTemplate: '/pet/{petId}', + executionParameters: [ + { name: 'api_key', in: 'header' }, + { name: 'petId', in: 'path' }, + ], + requestBodyContentType: undefined, + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'uploadfile', + { + name: 'uploadfile', + description: `Upload image of the pet.`, + inputSchema: { + type: 'object', + properties: { + petId: { type: 'number', format: 'int64', description: 'ID of pet to update' }, + additionalMetadata: { type: 'string', description: 'Additional Metadata' }, + requestBody: { + type: 'string', + description: 'Request body (content type: application/octet-stream)', + }, + }, + required: ['petId'], + }, + method: 'post', + pathTemplate: '/pet/{petId}/uploadImage', + executionParameters: [ + { name: 'petId', in: 'path' }, + { name: 'additionalMetadata', in: 'query' }, + ], + requestBodyContentType: 'application/octet-stream', + securityRequirements: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + ], + [ + 'getinventory', + { + name: 'getinventory', + description: `Returns a map of status codes to quantities.`, + inputSchema: { type: 'object', properties: {} }, + method: 'get', + pathTemplate: '/store/inventory', + executionParameters: [], + requestBodyContentType: undefined, + securityRequirements: [{ api_key: [] }], + }, + ], + [ + 'placeorder', + { + name: 'placeorder', + description: `Place a new order in the store.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + petId: { type: 'number', format: 'int64' }, + quantity: { type: 'number', format: 'int32' }, + shipDate: { type: 'string', format: 'date-time' }, + status: { + type: 'string', + description: 'Order Status', + enum: ['placed', 'approved', 'delivered'], + }, + complete: { type: 'boolean' }, + }, + description: 'The JSON request body.', + }, + }, + }, + method: 'post', + pathTemplate: '/store/order', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'getorderbyid', + { + name: 'getorderbyid', + description: `For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.`, + inputSchema: { + type: 'object', + properties: { + orderId: { + type: 'number', + format: 'int64', + description: 'ID of order that needs to be fetched', + }, + }, + required: ['orderId'], + }, + method: 'get', + pathTemplate: '/store/order/{orderId}', + executionParameters: [{ name: 'orderId', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'deleteorder', + { + name: 'deleteorder', + description: `For valid response try integer IDs with value < 1000. Anything above 1000 or non-integers will generate API errors.`, + inputSchema: { + type: 'object', + properties: { + orderId: { + type: 'number', + format: 'int64', + description: 'ID of the order that needs to be deleted', + }, + }, + required: ['orderId'], + }, + method: 'delete', + pathTemplate: '/store/order/{orderId}', + executionParameters: [{ name: 'orderId', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'createuser', + { + name: 'createuser', + description: `This can only be done by the logged in user.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + username: { type: 'string' }, + firstName: { type: 'string' }, + lastName: { type: 'string' }, + email: { type: 'string' }, + password: { type: 'string' }, + phone: { type: 'string' }, + userStatus: { type: 'number', description: 'User Status', format: 'int32' }, + }, + description: 'Created user object', + }, + }, + }, + method: 'post', + pathTemplate: '/user', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'createuserswithlistinput', + { + name: 'createuserswithlistinput', + description: `Creates list of users with given input array.`, + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + username: { type: 'string' }, + firstName: { type: 'string' }, + lastName: { type: 'string' }, + email: { type: 'string' }, + password: { type: 'string' }, + phone: { type: 'string' }, + userStatus: { type: 'number', description: 'User Status', format: 'int32' }, + }, + }, + description: 'The JSON request body.', + }, + }, + }, + method: 'post', + pathTemplate: '/user/createWithList', + executionParameters: [], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'loginuser', + { + name: 'loginuser', + description: `Log into the system.`, + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'The user name for login' }, + password: { type: 'string', description: 'The password for login in clear text' }, + }, + }, + method: 'get', + pathTemplate: '/user/login', + executionParameters: [ + { name: 'username', in: 'query' }, + { name: 'password', in: 'query' }, + ], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'logoutuser', + { + name: 'logoutuser', + description: `Log user out of the system.`, + inputSchema: { type: 'object', properties: {} }, + method: 'get', + pathTemplate: '/user/logout', + executionParameters: [], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'getuserbyname', + { + name: 'getuserbyname', + description: `Get user detail based on username.`, + inputSchema: { + type: 'object', + properties: { + username: { + type: 'string', + description: 'The name that needs to be fetched. Use user1 for testing', + }, + }, + required: ['username'], + }, + method: 'get', + pathTemplate: '/user/{username}', + executionParameters: [{ name: 'username', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], + [ + 'updateuser', + { + name: 'updateuser', + description: `This can only be done by the logged in user.`, + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'name that need to be deleted' }, + requestBody: { + type: 'object', + properties: { + id: { type: 'number', format: 'int64' }, + username: { type: 'string' }, + firstName: { type: 'string' }, + lastName: { type: 'string' }, + email: { type: 'string' }, + password: { type: 'string' }, + phone: { type: 'string' }, + userStatus: { type: 'number', description: 'User Status', format: 'int32' }, + }, + description: 'Update an existent user in the store', + }, + }, + required: ['username'], + }, + method: 'put', + pathTemplate: '/user/{username}', + executionParameters: [{ name: 'username', in: 'path' }], + requestBodyContentType: 'application/json', + securityRequirements: [], + }, + ], + [ + 'deleteuser', + { + name: 'deleteuser', + description: `This can only be done by the logged in user.`, + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'The name that needs to be deleted' }, + }, + required: ['username'], + }, + method: 'delete', + pathTemplate: '/user/{username}', + executionParameters: [{ name: 'username', in: 'path' }], + requestBodyContentType: undefined, + securityRequirements: [], + }, + ], ]); /** * Security schemes from the OpenAPI spec */ -const securitySchemes = { - "petstore_auth": { - "type": "oauth2", - "flows": { - "implicit": { - "authorizationUrl": "https://petstore3.swagger.io/oauth/authorize", - "scopes": { - "write:pets": "modify pets in your account", - "read:pets": "read your pets" - } - } - } +const securitySchemes = { + petstore_auth: { + type: 'oauth2', + flows: { + implicit: { + authorizationUrl: 'https://petstore3.swagger.io/oauth/authorize', + scopes: { + 'write:pets': 'modify pets in your account', + 'read:pets': 'read your pets', + }, + }, }, - "api_key": { - "type": "apiKey", - "name": "api_key", - "in": "header" - } - }; - + }, + api_key: { + type: 'apiKey', + name: 'api_key', + in: 'header', + }, +}; server.setRequestHandler(ListToolsRequestSchema, async () => { - const toolsForClient: Tool[] = Array.from(toolDefinitionMap.values()).map(def => ({ + const toolsForClient: Tool[] = Array.from(toolDefinitionMap.values()).map((def) => ({ name: def.name, description: def.description, - inputSchema: def.inputSchema + inputSchema: def.inputSchema, })); return { tools: toolsForClient }; }); - -server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest): Promise => { - const { name: toolName, arguments: toolArgs } = request.params; - const toolDefinition = toolDefinitionMap.get(toolName); - if (!toolDefinition) { - console.error(`Error: Unknown tool requested: ${toolName}`); - return { content: [{ type: "text", text: `Error: Unknown tool requested: ${toolName}` }] }; +server.setRequestHandler( + CallToolRequestSchema, + async (request: CallToolRequest): Promise => { + const { name: toolName, arguments: toolArgs } = request.params; + const toolDefinition = toolDefinitionMap.get(toolName); + if (!toolDefinition) { + console.error(`Error: Unknown tool requested: ${toolName}`); + return { content: [{ type: 'text', text: `Error: Unknown tool requested: ${toolName}` }] }; + } + return await executeApiTool(toolName, toolDefinition, toolArgs ?? {}, securitySchemes); } - return await executeApiTool(toolName, toolDefinition, toolArgs ?? {}, securitySchemes); -}); - - +); /** * Type definition for cached OAuth tokens */ interface TokenCacheEntry { - token: string; - expiresAt: number; + token: string; + expiresAt: number; } /** * Declare global __oauthTokenCache property for TypeScript */ declare global { - var __oauthTokenCache: Record | undefined; + var __oauthTokenCache: Record | undefined; } /** * Acquires an OAuth2 token using client credentials flow - * + * * @param schemeName Name of the security scheme * @param scheme OAuth2 security scheme * @returns Acquired token or null if unable to acquire */ -async function acquireOAuth2Token(schemeName: string, scheme: any): Promise { - try { - // Check if we have the necessary credentials - const clientId = process.env[`OAUTH_CLIENT_ID_SCHEMENAME`]; - const clientSecret = process.env[`OAUTH_CLIENT_SECRET_SCHEMENAME`]; - const scopes = process.env[`OAUTH_SCOPES_SCHEMENAME`]; - - if (!clientId || !clientSecret) { - console.error(`Missing client credentials for OAuth2 scheme '${schemeName}'`); - return null; - } - - // Initialize token cache if needed - if (typeof global.__oauthTokenCache === 'undefined') { - global.__oauthTokenCache = {}; - } - - // Check if we have a cached token - const cacheKey = `${schemeName}_${clientId}`; - const cachedToken = global.__oauthTokenCache[cacheKey]; - const now = Date.now(); - - if (cachedToken && cachedToken.expiresAt > now) { - console.error(`Using cached OAuth2 token for '${schemeName}' (expires in ${Math.floor((cachedToken.expiresAt - now) / 1000)} seconds)`); - return cachedToken.token; - } - - // Determine token URL based on flow type - let tokenUrl = ''; - if (scheme.flows?.clientCredentials?.tokenUrl) { - tokenUrl = scheme.flows.clientCredentials.tokenUrl; - console.error(`Using client credentials flow for '${schemeName}'`); - } else if (scheme.flows?.password?.tokenUrl) { - tokenUrl = scheme.flows.password.tokenUrl; - console.error(`Using password flow for '${schemeName}'`); - } else { - console.error(`No supported OAuth2 flow found for '${schemeName}'`); - return null; - } - - // Prepare the token request - let formData = new URLSearchParams(); - formData.append('grant_type', 'client_credentials'); - - // Add scopes if specified - if (scopes) { - formData.append('scope', scopes); - } - - console.error(`Requesting OAuth2 token from ${tokenUrl}`); - - // Make the token request - const response = await axios({ - method: 'POST', - url: tokenUrl, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Authorization': `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}` - }, - data: formData.toString() - }); - - // Process the response - if (response.data?.access_token) { - const token = response.data.access_token; - const expiresIn = response.data.expires_in || 3600; // Default to 1 hour - - // Cache the token - global.__oauthTokenCache[cacheKey] = { - token, - expiresAt: now + (expiresIn * 1000) - 60000 // Expire 1 minute early - }; - - console.error(`Successfully acquired OAuth2 token for '${schemeName}' (expires in ${expiresIn} seconds)`); - return token; - } else { - console.error(`Failed to acquire OAuth2 token for '${schemeName}': No access_token in response`); - return null; - } - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : String(error); - console.error(`Error acquiring OAuth2 token for '${schemeName}':`, errorMessage); - return null; - } -} +async function acquireOAuth2Token( + schemeName: string, + scheme: any +): Promise { + try { + // Check if we have the necessary credentials + const clientId = process.env[`OAUTH_CLIENT_ID_SCHEMENAME`]; + const clientSecret = process.env[`OAUTH_CLIENT_SECRET_SCHEMENAME`]; + const scopes = process.env[`OAUTH_SCOPES_SCHEMENAME`]; + if (!clientId || !clientSecret) { + console.error(`Missing client credentials for OAuth2 scheme '${schemeName}'`); + return null; + } + + // Initialize token cache if needed + if (typeof global.__oauthTokenCache === 'undefined') { + global.__oauthTokenCache = {}; + } + + // Check if we have a cached token + const cacheKey = `${schemeName}_${clientId}`; + const cachedToken = global.__oauthTokenCache[cacheKey]; + const now = Date.now(); + + if (cachedToken && cachedToken.expiresAt > now) { + console.error( + `Using cached OAuth2 token for '${schemeName}' (expires in ${Math.floor((cachedToken.expiresAt - now) / 1000)} seconds)` + ); + return cachedToken.token; + } + + // Determine token URL based on flow type + let tokenUrl = ''; + if (scheme.flows?.clientCredentials?.tokenUrl) { + tokenUrl = scheme.flows.clientCredentials.tokenUrl; + console.error(`Using client credentials flow for '${schemeName}'`); + } else if (scheme.flows?.password?.tokenUrl) { + tokenUrl = scheme.flows.password.tokenUrl; + console.error(`Using password flow for '${schemeName}'`); + } else { + console.error(`No supported OAuth2 flow found for '${schemeName}'`); + return null; + } + + // Prepare the token request + let formData = new URLSearchParams(); + formData.append('grant_type', 'client_credentials'); + + // Add scopes if specified + if (scopes) { + formData.append('scope', scopes); + } + + console.error(`Requesting OAuth2 token from ${tokenUrl}`); + + // Make the token request + const response = await axios({ + method: 'POST', + url: tokenUrl, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`, + }, + data: formData.toString(), + }); + + // Process the response + if (response.data?.access_token) { + const token = response.data.access_token; + const expiresIn = response.data.expires_in || 3600; // Default to 1 hour + + // Cache the token + global.__oauthTokenCache[cacheKey] = { + token, + expiresAt: now + expiresIn * 1000 - 60000, // Expire 1 minute early + }; + + console.error( + `Successfully acquired OAuth2 token for '${schemeName}' (expires in ${expiresIn} seconds)` + ); + return token; + } else { + console.error( + `Failed to acquire OAuth2 token for '${schemeName}': No access_token in response` + ); + return null; + } + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : String(error); + console.error(`Error acquiring OAuth2 token for '${schemeName}':`, errorMessage); + return null; + } +} /** * Executes an API tool with the provided arguments - * + * * @param toolName Name of the tool to execute * @param definition Tool definition * @param toolArgs Arguments provided by the user @@ -419,304 +728,334 @@ async function acquireOAuth2Token(schemeName: string, scheme: any): Promise + toolName: string, + definition: McpToolDefinition, + toolArgs: JsonObject, + allSecuritySchemes: Record ): Promise { try { // Validate arguments against the input schema let validatedArgs: JsonObject; try { - const zodSchema = getZodSchemaFromJsonSchema(definition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); + const zodSchema = getZodSchemaFromJsonSchema(definition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); } catch (error: unknown) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - const errorMessage = error instanceof Error ? error.message : String(error); - return { content: [{ type: 'text', text: `Internal error during validation setup: ${errorMessage}` }] }; - } + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + const errorMessage = error instanceof Error ? error.message : String(error); + return { + content: [ + { type: 'text', text: `Internal error during validation setup: ${errorMessage}` }, + ], + }; + } } // Prepare URL, query parameters, headers, and request body let urlPath = definition.pathTemplate; const queryParams: Record = {}; - const headers: Record = { 'Accept': 'application/json' }; + const headers: Record = { Accept: 'application/json' }; let requestBodyData: any = undefined; // Apply parameters to the URL path, query, or headers definition.executionParameters.forEach((param) => { - const value = validatedArgs[param.name]; - if (typeof value !== 'undefined' && value !== null) { - if (param.in === 'path') { - urlPath = urlPath.replace(`{${param.name}}`, encodeURIComponent(String(value))); - } - else if (param.in === 'query') { - queryParams[param.name] = value; - } - else if (param.in === 'header') { - headers[param.name.toLowerCase()] = String(value); - } + const value = validatedArgs[param.name]; + if (typeof value !== 'undefined' && value !== null) { + if (param.in === 'path') { + urlPath = urlPath.replace(`{${param.name}}`, encodeURIComponent(String(value))); + } else if (param.in === 'query') { + queryParams[param.name] = value; + } else if (param.in === 'header') { + headers[param.name.toLowerCase()] = String(value); } + } }); // Ensure all path parameters are resolved if (urlPath.includes('{')) { - throw new Error(`Failed to resolve path parameters: ${urlPath}`); + throw new Error(`Failed to resolve path parameters: ${urlPath}`); } - + // Construct the full URL const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; // Handle request body if needed if (definition.requestBodyContentType && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - headers['content-type'] = definition.requestBodyContentType; + requestBodyData = validatedArgs['requestBody']; + headers['content-type'] = definition.requestBodyContentType; } - // Apply security requirements if available // Security requirements use OR between array items and AND within each object - const appliedSecurity = definition.securityRequirements?.find(req => { - // Try each security requirement (combined with OR) - return Object.entries(req).every(([schemeName, scopesArray]) => { - const scheme = allSecuritySchemes[schemeName]; - if (!scheme) return false; - - // API Key security (header, query, cookie) - if (scheme.type === 'apiKey') { - return !!process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + const appliedSecurity = definition.securityRequirements?.find((req) => { + // Try each security requirement (combined with OR) + return Object.entries(req).every(([schemeName, scopesArray]) => { + const scheme = allSecuritySchemes[schemeName]; + if (!scheme) return false; + + // API Key security (header, query, cookie) + if (scheme.type === 'apiKey') { + return !!process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + } + + // HTTP security (basic, bearer) + if (scheme.type === 'http') { + if (scheme.scheme?.toLowerCase() === 'bearer') { + return !!process.env[ + `BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + } else if (scheme.scheme?.toLowerCase() === 'basic') { + return ( + !!process.env[ + `BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] && + !!process.env[ + `BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] + ); + } + } + + // OAuth2 security + if (scheme.type === 'oauth2') { + // Check for pre-existing token + if ( + process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`] + ) { + return true; + } + + // Check for client credentials for auto-acquisition + if ( + process.env[ + `OAUTH_CLIENT_ID_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] && + process.env[ + `OAUTH_CLIENT_SECRET_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ] + ) { + // Verify we have a supported flow + if (scheme.flows?.clientCredentials || scheme.flows?.password) { + return true; } - - // HTTP security (basic, bearer) - if (scheme.type === 'http') { - if (scheme.scheme?.toLowerCase() === 'bearer') { - return !!process.env[`BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - } - else if (scheme.scheme?.toLowerCase() === 'basic') { - return !!process.env[`BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`] && - !!process.env[`BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - } - } - - // OAuth2 security - if (scheme.type === 'oauth2') { - // Check for pre-existing token - if (process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]) { - return true; - } - - // Check for client credentials for auto-acquisition - if (process.env[`OAUTH_CLIENT_ID_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`] && - process.env[`OAUTH_CLIENT_SECRET_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]) { - // Verify we have a supported flow - if (scheme.flows?.clientCredentials || scheme.flows?.password) { - return true; - } - } - - return false; - } - - // OpenID Connect - if (scheme.type === 'openIdConnect') { - return !!process.env[`OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - } - - return false; - }); + } + + return false; + } + + // OpenID Connect + if (scheme.type === 'openIdConnect') { + return !!process.env[ + `OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + } + + return false; + }); }); // If we found matching security scheme(s), apply them if (appliedSecurity) { - // Apply each security scheme from this requirement (combined with AND) - for (const [schemeName, scopesArray] of Object.entries(appliedSecurity)) { - const scheme = allSecuritySchemes[schemeName]; - - // API Key security - if (scheme?.type === 'apiKey') { - const apiKey = process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (apiKey) { - if (scheme.in === 'header') { - headers[scheme.name.toLowerCase()] = apiKey; - console.error(`Applied API key '${schemeName}' in header '${scheme.name}'`); - } - else if (scheme.in === 'query') { - queryParams[scheme.name] = apiKey; - console.error(`Applied API key '${schemeName}' in query parameter '${scheme.name}'`); - } - else if (scheme.in === 'cookie') { - // Add the cookie, preserving other cookies if they exist - headers['cookie'] = `${scheme.name}=${apiKey}${headers['cookie'] ? `; ${headers['cookie']}` : ''}`; - console.error(`Applied API key '${schemeName}' in cookie '${scheme.name}'`); - } - } - } - // HTTP security (Bearer or Basic) - else if (scheme?.type === 'http') { - if (scheme.scheme?.toLowerCase() === 'bearer') { - const token = process.env[`BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (token) { - headers['authorization'] = `Bearer ${token}`; - console.error(`Applied Bearer token for '${schemeName}'`); - } - } - else if (scheme.scheme?.toLowerCase() === 'basic') { - const username = process.env[`BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - const password = process.env[`BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (username && password) { - headers['authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`; - console.error(`Applied Basic authentication for '${schemeName}'`); - } - } - } - // OAuth2 security - else if (scheme?.type === 'oauth2') { - // First try to use a pre-provided token - let token = process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - - // If no token but we have client credentials, try to acquire a token - if (!token && (scheme.flows?.clientCredentials || scheme.flows?.password)) { - console.error(`Attempting to acquire OAuth token for '${schemeName}'`); - token = (await acquireOAuth2Token(schemeName, scheme)) ?? ''; - } - - // Apply token if available - if (token) { - headers['authorization'] = `Bearer ${token}`; - console.error(`Applied OAuth2 token for '${schemeName}'`); - - // List the scopes that were requested, if any - const scopes = scopesArray as string[]; - if (scopes && scopes.length > 0) { - console.error(`Requested scopes: ${scopes.join(', ')}`); - } - } - } - // OpenID Connect - else if (scheme?.type === 'openIdConnect') { - const token = process.env[`OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; - if (token) { - headers['authorization'] = `Bearer ${token}`; - console.error(`Applied OpenID Connect token for '${schemeName}'`); - - // List the scopes that were requested, if any - const scopes = scopesArray as string[]; - if (scopes && scopes.length > 0) { - console.error(`Requested scopes: ${scopes.join(', ')}`); - } - } + // Apply each security scheme from this requirement (combined with AND) + for (const [schemeName, scopesArray] of Object.entries(appliedSecurity)) { + const scheme = allSecuritySchemes[schemeName]; + + // API Key security + if (scheme?.type === 'apiKey') { + const apiKey = + process.env[`API_KEY_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + if (apiKey) { + if (scheme.in === 'header') { + headers[scheme.name.toLowerCase()] = apiKey; + console.error(`Applied API key '${schemeName}' in header '${scheme.name}'`); + } else if (scheme.in === 'query') { + queryParams[scheme.name] = apiKey; + console.error(`Applied API key '${schemeName}' in query parameter '${scheme.name}'`); + } else if (scheme.in === 'cookie') { + // Add the cookie, preserving other cookies if they exist + headers['cookie'] = + `${scheme.name}=${apiKey}${headers['cookie'] ? `; ${headers['cookie']}` : ''}`; + console.error(`Applied API key '${schemeName}' in cookie '${scheme.name}'`); } + } } - } + // HTTP security (Bearer or Basic) + else if (scheme?.type === 'http') { + if (scheme.scheme?.toLowerCase() === 'bearer') { + const token = + process.env[`BEARER_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + if (token) { + headers['authorization'] = `Bearer ${token}`; + console.error(`Applied Bearer token for '${schemeName}'`); + } + } else if (scheme.scheme?.toLowerCase() === 'basic') { + const username = + process.env[ + `BASIC_USERNAME_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + const password = + process.env[ + `BASIC_PASSWORD_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}` + ]; + if (username && password) { + headers['authorization'] = + `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`; + console.error(`Applied Basic authentication for '${schemeName}'`); + } + } + } + // OAuth2 security + else if (scheme?.type === 'oauth2') { + // First try to use a pre-provided token + let token = + process.env[`OAUTH_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + + // If no token but we have client credentials, try to acquire a token + if (!token && (scheme.flows?.clientCredentials || scheme.flows?.password)) { + console.error(`Attempting to acquire OAuth token for '${schemeName}'`); + token = (await acquireOAuth2Token(schemeName, scheme)) ?? ''; + } + + // Apply token if available + if (token) { + headers['authorization'] = `Bearer ${token}`; + console.error(`Applied OAuth2 token for '${schemeName}'`); + + // List the scopes that were requested, if any + const scopes = scopesArray as string[]; + if (scopes && scopes.length > 0) { + console.error(`Requested scopes: ${scopes.join(', ')}`); + } + } + } + // OpenID Connect + else if (scheme?.type === 'openIdConnect') { + const token = + process.env[`OPENID_TOKEN_${schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`]; + if (token) { + headers['authorization'] = `Bearer ${token}`; + console.error(`Applied OpenID Connect token for '${schemeName}'`); + + // List the scopes that were requested, if any + const scopes = scopesArray as string[]; + if (scopes && scopes.length > 0) { + console.error(`Requested scopes: ${scopes.join(', ')}`); + } + } + } + } + } // Log warning if security is required but not available else if (definition.securityRequirements?.length > 0) { - // First generate a more readable representation of the security requirements - const securityRequirementsString = definition.securityRequirements - .map(req => { - const parts = Object.entries(req) - .map(([name, scopesArray]) => { - const scopes = scopesArray as string[]; - if (scopes.length === 0) return name; - return `${name} (scopes: ${scopes.join(', ')})`; - }) - .join(' AND '); - return `[${parts}]`; + // First generate a more readable representation of the security requirements + const securityRequirementsString = definition.securityRequirements + .map((req) => { + const parts = Object.entries(req) + .map(([name, scopesArray]) => { + const scopes = scopesArray as string[]; + if (scopes.length === 0) return name; + return `${name} (scopes: ${scopes.join(', ')})`; }) - .join(' OR '); - - console.warn(`Tool '${toolName}' requires security: ${securityRequirementsString}, but no suitable credentials found.`); + .join(' AND '); + return `[${parts}]`; + }) + .join(' OR '); + + console.warn( + `Tool '${toolName}' requires security: ${securityRequirementsString}, but no suitable credentials found.` + ); } - // Prepare the axios request configuration const config: AxiosRequestConfig = { - method: definition.method.toUpperCase(), - url: requestUrl, - params: queryParams, + method: definition.method.toUpperCase(), + url: requestUrl, + params: queryParams, headers: headers, ...(requestBodyData !== undefined && { data: requestBodyData }), }; // Log request info to stderr (doesn't affect MCP output) console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - + // Execute the request const response = await axios(config); // Process and format the response let responseText = ''; const contentType = response.headers['content-type']?.toLowerCase() || ''; - + // Handle JSON responses - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { - responseText = JSON.stringify(response.data, null, 2); - } catch (e) { - responseText = "[Stringify Error]"; - } - } + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Stringify Error]'; + } + } // Handle string responses - else if (typeof response.data === 'string') { - responseText = response.data; + else if (typeof response.data === 'string') { + responseText = response.data; } // Handle other response types - else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); + else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); } // Handle empty responses - else { - responseText = `(Status: ${response.status} - No body content)`; + else { + responseText = `(Status: ${response.status} - No body content)`; } - - // Return formatted response - return { - content: [ - { - type: "text", - text: `API Response (Status: ${response.status}):\n${responseText}` - } - ], - }; + // Return formatted response + return { + content: [ + { + type: 'text', + text: `API Response (Status: ${response.status}):\n${responseText}`, + }, + ], + }; } catch (error: unknown) { // Handle errors during execution let errorMessage: string; - + // Format Axios errors specially - if (axios.isAxiosError(error)) { - errorMessage = formatApiError(error); + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); } // Handle standard errors - else if (error instanceof Error) { - errorMessage = error.message; + else if (error instanceof Error) { + errorMessage = error.message; } // Handle unexpected error types - else { - errorMessage = 'Unexpected error: ' + String(error); + else { + errorMessage = 'Unexpected error: ' + String(error); } - + // Log error to stderr console.error(`Error during execution of tool '${toolName}':`, errorMessage); - + // Return error message to client - return { content: [{ type: "text", text: errorMessage }] }; + return { content: [{ type: 'text', text: errorMessage }] }; } } - /** * Main function to start the server */ async function main() { -// Set up StreamableHTTP transport + // Set up StreamableHTTP transport try { await setupStreamableHttpServer(server, 3000); } catch (error) { - console.error("Error setting up StreamableHTTP server:", error); + console.error('Error setting up StreamableHTTP server:', error); process.exit(1); } } @@ -725,8 +1064,8 @@ async function main() { * Cleanup function for graceful shutdown */ async function cleanup() { - console.error("Shutting down MCP server..."); - process.exit(0); + console.error('Shutting down MCP server...'); + process.exit(0); } // Register signal handlers @@ -735,65 +1074,63 @@ process.on('SIGTERM', cleanup); // Start the server main().catch((error) => { - console.error("Fatal error in main execution:", error); + console.error('Fatal error in main execution:', error); process.exit(1); }); /** * Formats API errors for better readability - * + * * @param error Axios error * @returns Formatted error message */ function formatApiError(error: AxiosError): string { - let message = 'API request failed.'; - if (error.response) { - message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `; - const responseData = error.response.data; - const MAX_LEN = 200; - if (typeof responseData === 'string') { - message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`; - } - else if (responseData) { - try { - const jsonString = JSON.stringify(responseData); - message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`; - } catch { - message += 'Response: [Could not serialize data]'; - } - } - else { - message += 'No response body received.'; - } - } else if (error.request) { - message = 'API Network Error: No response received from server.'; - if (error.code) message += ` (Code: ${error.code})`; - } else { - message += `API Request Setup Error: ${error.message}`; + let message = 'API request failed.'; + if (error.response) { + message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `; + const responseData = error.response.data; + const MAX_LEN = 200; + if (typeof responseData === 'string') { + message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`; + } else if (responseData) { + try { + const jsonString = JSON.stringify(responseData); + message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`; + } catch { + message += 'Response: [Could not serialize data]'; + } + } else { + message += 'No response body received.'; } - return message; + } else if (error.request) { + message = 'API Network Error: No response received from server.'; + if (error.code) message += ` (Code: ${error.code})`; + } else { + message += `API Request Setup Error: ${error.message}`; + } + return message; } /** * Converts a JSON Schema to a Zod schema for runtime validation - * + * * @param jsonSchema JSON Schema * @param toolName Tool name for error reporting * @returns Zod schema */ function getZodSchemaFromJsonSchema(jsonSchema: any, toolName: string): z.ZodTypeAny { - if (typeof jsonSchema !== 'object' || jsonSchema === null) { - return z.object({}).passthrough(); - } - try { - const zodSchemaString = jsonSchemaToZod(jsonSchema); - const zodSchema = eval(zodSchemaString); - if (typeof zodSchema?.parse !== 'function') { - throw new Error('Eval did not produce a valid Zod schema.'); - } - return zodSchema as z.ZodTypeAny; - } catch (err: any) { - console.error(`Failed to generate/evaluate Zod schema for '${toolName}':`, err); - return z.object({}).passthrough(); + if (typeof jsonSchema !== 'object' || jsonSchema === null) { + return z.object({}).passthrough(); + } + try { + const zodSchemaString = jsonSchemaToZod(jsonSchema); + const zodSchema = eval(zodSchemaString); + if (typeof zodSchema?.parse !== 'function') { + throw new Error('Eval did not produce a valid Zod schema.'); } + return zodSchema as z.ZodTypeAny; + } catch (err: any) { + console.error(`Failed to generate/evaluate Zod schema for '${toolName}':`, err); + return z.object({}).passthrough(); + } } diff --git a/examples/pet-store-streamable-http/src/streamable-http.ts b/examples/pet-store-streamable-http/src/streamable-http.ts index fb3d364..618cbe7 100644 --- a/examples/pet-store-streamable-http/src/streamable-http.ts +++ b/examples/pet-store-streamable-http/src/streamable-http.ts @@ -1,4 +1,3 @@ - /** * StreamableHTTP server setup for HTTP-based MCP communication using Hono */ @@ -6,17 +5,17 @@ import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { serve } from '@hono/node-server'; import { v4 as uuid } from 'uuid'; -import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { InitializeRequestSchema, JSONRPCError } from "@modelcontextprotocol/sdk/types.js"; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { InitializeRequestSchema, JSONRPCError } from '@modelcontextprotocol/sdk/types.js'; import { toReqRes, toFetchResponse } from 'fetch-to-node'; // Import server configuration constants import { SERVER_NAME, SERVER_VERSION } from './index.js'; // Constants -const SESSION_ID_HEADER_NAME = "mcp-session-id"; -const JSON_RPC = "2.0"; +const SESSION_ID_HEADER_NAME = 'mcp-session-id'; +const JSON_RPC = '2.0'; /** * StreamableHTTP MCP Server handler @@ -24,106 +23,102 @@ const JSON_RPC = "2.0"; class MCPStreamableHttpServer { server: Server; // Store active transports by session ID - transports: {[sessionId: string]: StreamableHTTPServerTransport} = {}; - + transports: { [sessionId: string]: StreamableHTTPServerTransport } = {}; + constructor(server: Server) { this.server = server; } - + /** * Handle GET requests (typically used for static files) */ async handleGetRequest(c: any) { - console.error("GET request received - StreamableHTTP transport only supports POST"); + console.error('GET request received - StreamableHTTP transport only supports POST'); return c.text('Method Not Allowed', 405, { - 'Allow': 'POST' + Allow: 'POST', }); } - + /** * Handle POST requests (all MCP communication) */ async handlePostRequest(c: any) { const sessionId = c.req.header(SESSION_ID_HEADER_NAME); - console.error(`POST request received ${sessionId ? 'with session ID: ' + sessionId : 'without session ID'}`); - + console.error( + `POST request received ${sessionId ? 'with session ID: ' + sessionId : 'without session ID'}` + ); + try { const body = await c.req.json(); - + // Convert Fetch Request to Node.js req/res const { req, res } = toReqRes(c.req.raw); - + // Reuse existing transport if we have a session ID if (sessionId && this.transports[sessionId]) { const transport = this.transports[sessionId]; - + // Handle the request with the transport await transport.handleRequest(req, res, body); - + // Cleanup when the response ends res.on('close', () => { console.error(`Request closed for session ${sessionId}`); }); - + // Convert Node.js response back to Fetch Response return toFetchResponse(res); } - + // Create new transport for initialize requests if (!sessionId && this.isInitializeRequest(body)) { - console.error("Creating new StreamableHTTP transport for initialize request"); - + console.error('Creating new StreamableHTTP transport for initialize request'); + const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => uuid(), }); - + // Add error handler for debug purposes transport.onerror = (err) => { console.error('StreamableHTTP transport error:', err); }; - + // Connect the transport to the MCP server await this.server.connect(transport); - + // Handle the request with the transport await transport.handleRequest(req, res, body); - + // Store the transport if we have a session ID const newSessionId = transport.sessionId; if (newSessionId) { console.error(`New session established: ${newSessionId}`); this.transports[newSessionId] = transport; - + // Set up clean-up for when the transport is closed transport.onclose = () => { console.error(`Session closed: ${newSessionId}`); delete this.transports[newSessionId]; }; } - + // Cleanup when the response ends res.on('close', () => { console.error(`Request closed for new session`); }); - + // Convert Node.js response back to Fetch Response return toFetchResponse(res); } - + // Invalid request (no session ID and not initialize) - return c.json( - this.createErrorResponse("Bad Request: invalid session ID or method."), - 400 - ); + return c.json(this.createErrorResponse('Bad Request: invalid session ID or method.'), 400); } catch (error) { console.error('Error handling MCP request:', error); - return c.json( - this.createErrorResponse("Internal server error."), - 500 - ); + return c.json(this.createErrorResponse('Internal server error.'), 500); } } - + /** * Create a JSON-RPC error response */ @@ -137,7 +132,7 @@ class MCPStreamableHttpServer { id: uuid(), }; } - + /** * Check if the request is an initialize request */ @@ -146,18 +141,18 @@ class MCPStreamableHttpServer { const result = InitializeRequestSchema.safeParse(data); return result.success; }; - + if (Array.isArray(body)) { - return body.some(request => isInitial(request)); + return body.some((request) => isInitial(request)); } - + return isInitial(body); } } /** * Sets up a web server for the MCP server using StreamableHTTP transport - * + * * @param server The MCP Server instance * @param port The port to listen on (default: 3000) * @returns The Hono app instance @@ -165,22 +160,22 @@ class MCPStreamableHttpServer { export async function setupStreamableHttpServer(server: Server, port = 3000) { // Create Hono app const app = new Hono(); - + // Enable CORS app.use('*', cors()); - + // Create MCP handler const mcpHandler = new MCPStreamableHttpServer(server); - + // Add a simple health check endpoint app.get('/health', (c) => { return c.json({ status: 'OK', server: SERVER_NAME, version: SERVER_VERSION }); }); - + // Main MCP endpoint supporting both GET and POST - app.get("/mcp", (c) => mcpHandler.handleGetRequest(c)); - app.post("/mcp", (c) => mcpHandler.handlePostRequest(c)); - + app.get('/mcp', (c) => mcpHandler.handleGetRequest(c)); + app.post('/mcp', (c) => mcpHandler.handlePostRequest(c)); + // Static files for the web client (if any) app.get('/*', async (c) => { const filePath = c.req.path === '/' ? '/index.html' : c.req.path; @@ -189,37 +184,51 @@ export async function setupStreamableHttpServer(server: Server, port = 3000) { const fs = await import('fs'); const path = await import('path'); const { fileURLToPath } = await import('url'); - + const __dirname = path.dirname(fileURLToPath(import.meta.url)); const publicPath = path.join(__dirname, '..', '..', 'public'); const fullPath = path.join(publicPath, filePath); - + // Simple security check to prevent directory traversal if (!fullPath.startsWith(publicPath)) { return c.text('Forbidden', 403); } - + try { const stat = fs.statSync(fullPath); if (stat.isFile()) { const content = fs.readFileSync(fullPath); - + // Set content type based on file extension const ext = path.extname(fullPath).toLowerCase(); let contentType = 'text/plain'; - + switch (ext) { - case '.html': contentType = 'text/html'; break; - case '.css': contentType = 'text/css'; break; - case '.js': contentType = 'text/javascript'; break; - case '.json': contentType = 'application/json'; break; - case '.png': contentType = 'image/png'; break; - case '.jpg': contentType = 'image/jpeg'; break; - case '.svg': contentType = 'image/svg+xml'; break; + case '.html': + contentType = 'text/html'; + break; + case '.css': + contentType = 'text/css'; + break; + case '.js': + contentType = 'text/javascript'; + break; + case '.json': + contentType = 'application/json'; + break; + case '.png': + contentType = 'image/png'; + break; + case '.jpg': + contentType = 'image/jpeg'; + break; + case '.svg': + contentType = 'image/svg+xml'; + break; } - + return new Response(content, { - headers: { 'Content-Type': contentType } + headers: { 'Content-Type': contentType }, }); } } catch (err) { @@ -230,19 +239,22 @@ export async function setupStreamableHttpServer(server: Server, port = 3000) { console.error('Error serving static file:', err); return c.text('Internal Server Error', 500); } - + return c.text('Not Found', 404); }); - + // Start the server - serve({ - fetch: app.fetch, - port - }, (info) => { - console.error(`MCP StreamableHTTP Server running at http://localhost:${info.port}`); - console.error(`- MCP Endpoint: http://localhost:${info.port}/mcp`); - console.error(`- Health Check: http://localhost:${info.port}/health`); - }); - + serve( + { + fetch: app.fetch, + port, + }, + (info) => { + console.error(`MCP StreamableHTTP Server running at http://localhost:${info.port}`); + console.error(`- MCP Endpoint: http://localhost:${info.port}/mcp`); + console.error(`- Health Check: http://localhost:${info.port}/health`); + } + ); + return app; } diff --git a/examples/pet-store-streamable-http/tsconfig.json b/examples/pet-store-streamable-http/tsconfig.json index ed2966d..13e80dc 100644 --- a/examples/pet-store-streamable-http/tsconfig.json +++ b/examples/pet-store-streamable-http/tsconfig.json @@ -17,12 +17,6 @@ "sourceMap": true, "forceConsistentCasingInFileNames": true }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "build", - "**/*.test.ts" - ] -} \ No newline at end of file + "include": ["src/**/*"], + "exclude": ["node_modules", "build", "**/*.test.ts"] +} diff --git a/examples/petstore-mcp/src/index.ts b/examples/petstore-mcp/src/index.ts index 1ec7e71..218d389 100644 --- a/examples/petstore-mcp/src/index.ts +++ b/examples/petstore-mcp/src/index.ts @@ -1,10 +1,9 @@ - // Generated by openapi-to-mcp-generator for swagger-petstore---openapi-3-0 v1.0.26 // Source OpenAPI spec: https://petstore3.swagger.io/api/v3/openapi.json // Generation date: 2025-04-12T09:29:22.152Z -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; // Import Schemas and Types from /types subpath with .js extension import { @@ -12,8 +11,8 @@ import { ListToolsRequestSchema, type Tool, type CallToolResult, - type CallToolRequest // Added type for the request parameter -} from "@modelcontextprotocol/sdk/types.js"; + type CallToolRequest, // Added type for the request parameter +} from '@modelcontextprotocol/sdk/types.js'; // Zod for runtime validation import { z, ZodError } from 'zod'; @@ -26,587 +25,542 @@ type JsonObject = Record; import axios, { type AxiosRequestConfig, type AxiosError } from 'axios'; // --- Server Configuration --- -const SERVER_NAME = "swagger-petstore---openapi-3-0"; -const SERVER_VERSION = "1.0.26"; -const API_BASE_URL = "https://petstore3.swagger.io/api/v3"; +const SERVER_NAME = 'swagger-petstore---openapi-3-0'; +const SERVER_VERSION = '1.0.26'; +const API_BASE_URL = 'https://petstore3.swagger.io/api/v3'; // --- Server Instance --- const server = new Server( { name: SERVER_NAME, - version: SERVER_VERSION + version: SERVER_VERSION, }, { capabilities: { - tools: {} - } + tools: {}, + }, } ); // --- Tool Definitions (for ListTools response) --- // Corrected: Use Tool[] type const toolsList: Tool[] = [ - // Tool: updatePet (PUT /pet) { - name: "updatePet", + name: 'updatePet', description: `Update an existing pet by Id.`, - inputSchema: { - "type": "object", - "properties": { - "requestBody": { - "required": [ - "name", - "photoUrls" - ], - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "name": { - "type": "string" - }, - "category": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "name": { - "type": "string" - } - } - }, - "photoUrls": { - "type": "array", - "items": { - "type": "string" - } - }, - "tags": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "name": { - "type": "string" - } - } - } - }, - "status": { - "type": "string", - "description": "pet status in the store", - "enum": [ - "available", - "pending", - "sold" - ] - } + inputSchema: { + type: 'object', + properties: { + requestBody: { + required: ['name', 'photoUrls'], + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + name: { + type: 'string', + }, + category: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', }, - "description": "Update an existent pet in the store" - } + name: { + type: 'string', + }, + }, + }, + photoUrls: { + type: 'array', + items: { + type: 'string', + }, + }, + tags: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + name: { + type: 'string', + }, + }, + }, + }, + status: { + type: 'string', + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + }, + }, + description: 'Update an existent pet in the store', }, - "required": [ - "requestBody" - ] - } + }, + required: ['requestBody'], + }, }, // Tool: addPet (POST /pet) { - name: "addPet", + name: 'addPet', description: `Add a new pet to the store.`, - inputSchema: { - "type": "object", - "properties": { - "requestBody": { - "required": [ - "name", - "photoUrls" - ], - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "name": { - "type": "string" - }, - "category": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "name": { - "type": "string" - } - } - }, - "photoUrls": { - "type": "array", - "items": { - "type": "string" - } - }, - "tags": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "name": { - "type": "string" - } - } - } - }, - "status": { - "type": "string", - "description": "pet status in the store", - "enum": [ - "available", - "pending", - "sold" - ] - } + inputSchema: { + type: 'object', + properties: { + requestBody: { + required: ['name', 'photoUrls'], + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + name: { + type: 'string', + }, + category: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', }, - "description": "Create a new pet in the store" - } + name: { + type: 'string', + }, + }, + }, + photoUrls: { + type: 'array', + items: { + type: 'string', + }, + }, + tags: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + name: { + type: 'string', + }, + }, + }, + }, + status: { + type: 'string', + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + }, + }, + description: 'Create a new pet in the store', }, - "required": [ - "requestBody" - ] - } + }, + required: ['requestBody'], + }, }, // Tool: findPetsByStatus (GET /pet/findByStatus) { - name: "findPetsByStatus", + name: 'findPetsByStatus', description: `Multiple status values can be provided with comma separated strings.`, - inputSchema: { - "type": "object", - "properties": { - "status": { - "type": "string", - "default": "available", - "enum": [ - "available", - "pending", - "sold" - ], - "description": "Status values that need to be considered for filter" - } - } - } + inputSchema: { + type: 'object', + properties: { + status: { + type: 'string', + default: 'available', + enum: ['available', 'pending', 'sold'], + description: 'Status values that need to be considered for filter', + }, + }, + }, }, // Tool: findPetsByTags (GET /pet/findByTags) { - name: "findPetsByTags", + name: 'findPetsByTags', description: `Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.`, - inputSchema: { - "type": "object", - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags to filter by" - } - } - } + inputSchema: { + type: 'object', + properties: { + tags: { + type: 'array', + items: { + type: 'string', + }, + description: 'Tags to filter by', + }, + }, + }, }, // Tool: getPetById (GET /pet/{petId}) { - name: "getPetById", + name: 'getPetById', description: `Returns a single pet.`, - inputSchema: { - "type": "object", - "properties": { - "petId": { - "type": "number", - "format": "int64", - "description": "ID of pet to return" - } + inputSchema: { + type: 'object', + properties: { + petId: { + type: 'number', + format: 'int64', + description: 'ID of pet to return', }, - "required": [ - "petId" - ] - } + }, + required: ['petId'], + }, }, // Tool: updatePetWithForm (POST /pet/{petId}) { - name: "updatePetWithForm", + name: 'updatePetWithForm', description: `Updates a pet resource based on the form data.`, - inputSchema: { - "type": "object", - "properties": { - "petId": { - "type": "number", - "format": "int64", - "description": "ID of pet that needs to be updated" - }, - "name": { - "type": "string", - "description": "Name of pet that needs to be updated" - }, - "status": { - "type": "string", - "description": "Status of pet that needs to be updated" - } + inputSchema: { + type: 'object', + properties: { + petId: { + type: 'number', + format: 'int64', + description: 'ID of pet that needs to be updated', }, - "required": [ - "petId" - ] - } + name: { + type: 'string', + description: 'Name of pet that needs to be updated', + }, + status: { + type: 'string', + description: 'Status of pet that needs to be updated', + }, + }, + required: ['petId'], + }, }, // Tool: deletePet (DELETE /pet/{petId}) { - name: "deletePet", + name: 'deletePet', description: `Delete a pet.`, - inputSchema: { - "type": "object", - "properties": { - "api_key": { - "type": "string" - }, - "petId": { - "type": "number", - "format": "int64", - "description": "Pet id to delete" - } + inputSchema: { + type: 'object', + properties: { + api_key: { + type: 'string', }, - "required": [ - "petId" - ] - } + petId: { + type: 'number', + format: 'int64', + description: 'Pet id to delete', + }, + }, + required: ['petId'], + }, }, // Tool: uploadFile (POST /pet/{petId}/uploadImage) { - name: "uploadFile", + name: 'uploadFile', description: `Upload image of the pet.`, - inputSchema: { - "type": "object", - "properties": { - "petId": { - "type": "number", - "format": "int64", - "description": "ID of pet to update" - }, - "additionalMetadata": { - "type": "string", - "description": "Additional Metadata" - }, - "requestBody": { - "type": "string", - "description": "Request body (content type: application/octet-stream)" - } + inputSchema: { + type: 'object', + properties: { + petId: { + type: 'number', + format: 'int64', + description: 'ID of pet to update', }, - "required": [ - "petId" - ] - } + additionalMetadata: { + type: 'string', + description: 'Additional Metadata', + }, + requestBody: { + type: 'string', + description: 'Request body (content type: application/octet-stream)', + }, + }, + required: ['petId'], + }, }, // Tool: getInventory (GET /store/inventory) { - name: "getInventory", + name: 'getInventory', description: `Returns a map of status codes to quantities.`, - inputSchema: { - "type": "object", - "properties": {} - } + inputSchema: { + type: 'object', + properties: {}, + }, }, // Tool: placeOrder (POST /store/order) { - name: "placeOrder", + name: 'placeOrder', description: `Place a new order in the store.`, - inputSchema: { - "type": "object", - "properties": { - "requestBody": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "petId": { - "type": "number", - "format": "int64" - }, - "quantity": { - "type": "number", - "format": "int32" - }, - "shipDate": { - "type": "string", - "format": "date-time" - }, - "status": { - "type": "string", - "description": "Order Status", - "enum": [ - "placed", - "approved", - "delivered" - ] - }, - "complete": { - "type": "boolean" - } - }, - "description": "The JSON request body." - } - } - } + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + petId: { + type: 'number', + format: 'int64', + }, + quantity: { + type: 'number', + format: 'int32', + }, + shipDate: { + type: 'string', + format: 'date-time', + }, + status: { + type: 'string', + description: 'Order Status', + enum: ['placed', 'approved', 'delivered'], + }, + complete: { + type: 'boolean', + }, + }, + description: 'The JSON request body.', + }, + }, + }, }, // Tool: getOrderById (GET /store/order/{orderId}) { - name: "getOrderById", + name: 'getOrderById', description: `For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.`, - inputSchema: { - "type": "object", - "properties": { - "orderId": { - "type": "number", - "format": "int64", - "description": "ID of order that needs to be fetched" - } + inputSchema: { + type: 'object', + properties: { + orderId: { + type: 'number', + format: 'int64', + description: 'ID of order that needs to be fetched', }, - "required": [ - "orderId" - ] - } + }, + required: ['orderId'], + }, }, // Tool: deleteOrder (DELETE /store/order/{orderId}) { - name: "deleteOrder", + name: 'deleteOrder', description: `For valid response try integer IDs with value < 1000. Anything above 1000 or non-integers will generate API errors.`, - inputSchema: { - "type": "object", - "properties": { - "orderId": { - "type": "number", - "format": "int64", - "description": "ID of the order that needs to be deleted" - } + inputSchema: { + type: 'object', + properties: { + orderId: { + type: 'number', + format: 'int64', + description: 'ID of the order that needs to be deleted', }, - "required": [ - "orderId" - ] - } + }, + required: ['orderId'], + }, }, // Tool: createUser (POST /user) { - name: "createUser", + name: 'createUser', description: `This can only be done by the logged in user.`, - inputSchema: { - "type": "object", - "properties": { - "requestBody": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "username": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "phone": { - "type": "string" - }, - "userStatus": { - "type": "number", - "description": "User Status", - "format": "int32" - } - }, - "description": "Created user object" - } - } - } + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + username: { + type: 'string', + }, + firstName: { + type: 'string', + }, + lastName: { + type: 'string', + }, + email: { + type: 'string', + }, + password: { + type: 'string', + }, + phone: { + type: 'string', + }, + userStatus: { + type: 'number', + description: 'User Status', + format: 'int32', + }, + }, + description: 'Created user object', + }, + }, + }, }, // Tool: createUsersWithListInput (POST /user/createWithList) { - name: "createUsersWithListInput", + name: 'createUsersWithListInput', description: `Creates list of users with given input array.`, - inputSchema: { - "type": "object", - "properties": { - "requestBody": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "username": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "phone": { - "type": "string" - }, - "userStatus": { - "type": "number", - "description": "User Status", - "format": "int32" - } - } - }, - "description": "The JSON request body." - } - } - } + inputSchema: { + type: 'object', + properties: { + requestBody: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + username: { + type: 'string', + }, + firstName: { + type: 'string', + }, + lastName: { + type: 'string', + }, + email: { + type: 'string', + }, + password: { + type: 'string', + }, + phone: { + type: 'string', + }, + userStatus: { + type: 'number', + description: 'User Status', + format: 'int32', + }, + }, + }, + description: 'The JSON request body.', + }, + }, + }, }, // Tool: loginUser (GET /user/login) { - name: "loginUser", + name: 'loginUser', description: `Log into the system.`, - inputSchema: { - "type": "object", - "properties": { - "username": { - "type": "string", - "description": "The user name for login" - }, - "password": { - "type": "string", - "description": "The password for login in clear text" - } - } - } + inputSchema: { + type: 'object', + properties: { + username: { + type: 'string', + description: 'The user name for login', + }, + password: { + type: 'string', + description: 'The password for login in clear text', + }, + }, + }, }, // Tool: logoutUser (GET /user/logout) { - name: "logoutUser", + name: 'logoutUser', description: `Log user out of the system.`, - inputSchema: { - "type": "object", - "properties": {} - } + inputSchema: { + type: 'object', + properties: {}, + }, }, // Tool: getUserByName (GET /user/{username}) { - name: "getUserByName", + name: 'getUserByName', description: `Get user detail based on username.`, - inputSchema: { - "type": "object", - "properties": { - "username": { - "type": "string", - "description": "The name that needs to be fetched. Use user1 for testing" - } + inputSchema: { + type: 'object', + properties: { + username: { + type: 'string', + description: 'The name that needs to be fetched. Use user1 for testing', }, - "required": [ - "username" - ] - } + }, + required: ['username'], + }, }, // Tool: updateUser (PUT /user/{username}) { - name: "updateUser", + name: 'updateUser', description: `This can only be done by the logged in user.`, - inputSchema: { - "type": "object", - "properties": { - "username": { - "type": "string", - "description": "name that need to be deleted" - }, - "requestBody": { - "type": "object", - "properties": { - "id": { - "type": "number", - "format": "int64" - }, - "username": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "phone": { - "type": "string" - }, - "userStatus": { - "type": "number", - "description": "User Status", - "format": "int32" - } - }, - "description": "Update an existent user in the store" - } + inputSchema: { + type: 'object', + properties: { + username: { + type: 'string', + description: 'name that need to be deleted', }, - "required": [ - "username" - ] - } + requestBody: { + type: 'object', + properties: { + id: { + type: 'number', + format: 'int64', + }, + username: { + type: 'string', + }, + firstName: { + type: 'string', + }, + lastName: { + type: 'string', + }, + email: { + type: 'string', + }, + password: { + type: 'string', + }, + phone: { + type: 'string', + }, + userStatus: { + type: 'number', + description: 'User Status', + format: 'int32', + }, + }, + description: 'Update an existent user in the store', + }, + }, + required: ['username'], + }, }, // Tool: deleteUser (DELETE /user/{username}) { - name: "deleteUser", + name: 'deleteUser', description: `This can only be done by the logged in user.`, - inputSchema: { - "type": "object", - "properties": { - "username": { - "type": "string", - "description": "The name that needs to be deleted" - } + inputSchema: { + type: 'object', + properties: { + username: { + type: 'string', + description: 'The name that needs to be deleted', }, - "required": [ - "username" - ] - } + }, + required: ['username'], + }, }, ]; @@ -621,1523 +575,2069 @@ server.setRequestHandler(ListToolsRequestSchema, async () => { // 2. Call Tool Handler // Corrected: Added explicit type for 'request' parameter -server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest): Promise => { - const { name: toolName, arguments: toolArgs } = request.params; +server.setRequestHandler( + CallToolRequestSchema, + async (request: CallToolRequest): Promise => { + const { name: toolName, arguments: toolArgs } = request.params; - const toolDefinition = toolsList.find(t => t.name === toolName); + const toolDefinition = toolsList.find((t) => t.name === toolName); - if (!toolDefinition) { - console.error(`Error: Received request for unknown tool: ${toolName}`); - return { content: [{ type: "text", text: `Error: Unknown tool requested: ${toolName}` }] }; + if (!toolDefinition) { + console.error(`Error: Received request for unknown tool: ${toolName}`); + return { content: [{ type: 'text', text: `Error: Unknown tool requested: ${toolName}` }] }; + } + + // --- Tool Execution Logic --- + + // Handler for tool: updatePet + if (toolName === 'updatePet') { + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + // Set Content-Type based on OpenAPI spec (or fallback) + if (typeof validatedArgs?.['requestBody'] !== 'undefined') { + headers['content-type'] = 'application/json'; + } + + let requestBodyData: any = undefined; + if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { + requestBodyData = validatedArgs['requestBody']; + } + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'PUT', + url: requestUrl, + params: queryParams, + headers: headers, + data: requestBodyData, // Pass the prepared request body data // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'addPet') { + // Handler for tool: addPet + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + // Set Content-Type based on OpenAPI spec (or fallback) + if (typeof validatedArgs?.['requestBody'] !== 'undefined') { + headers['content-type'] = 'application/json'; + } + + let requestBodyData: any = undefined; + if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { + requestBodyData = validatedArgs['requestBody']; + } + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'POST', + url: requestUrl, + params: queryParams, + headers: headers, + data: requestBodyData, // Pass the prepared request body data // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'findPetsByStatus') { + // Handler for tool: findPetsByStatus + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet/findByStatus'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + const status_val = validatedArgs['status']; + if (typeof status_val !== 'undefined' && status_val !== null) + queryParams['status'] = status_val; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'findPetsByTags') { + // Handler for tool: findPetsByTags + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet/findByTags'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + const tags_val = validatedArgs['tags']; + if (typeof tags_val !== 'undefined' && tags_val !== null) queryParams['tags'] = tags_val; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'getPetById') { + // Handler for tool: getPetById + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet/{petId}'; + const petId_val = validatedArgs['petId']; + if (typeof petId_val !== 'undefined' && petId_val !== null) { + urlPath = urlPath.replace('{petId}', encodeURIComponent(String(petId_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'updatePetWithForm') { + // Handler for tool: updatePetWithForm + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet/{petId}'; + const petId_val = validatedArgs['petId']; + if (typeof petId_val !== 'undefined' && petId_val !== null) { + urlPath = urlPath.replace('{petId}', encodeURIComponent(String(petId_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + const name_val = validatedArgs['name']; + if (typeof name_val !== 'undefined' && name_val !== null) queryParams['name'] = name_val; + const status_val = validatedArgs['status']; + if (typeof status_val !== 'undefined' && status_val !== null) + queryParams['status'] = status_val; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'POST', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'deletePet') { + // Handler for tool: deletePet + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet/{petId}'; + const petId_val = validatedArgs['petId']; + if (typeof petId_val !== 'undefined' && petId_val !== null) { + urlPath = urlPath.replace('{petId}', encodeURIComponent(String(petId_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + const api_key_val = validatedArgs['api_key']; + if (typeof api_key_val !== 'undefined' && api_key_val !== null) + headers['api_key'] = String(api_key_val); + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'DELETE', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'uploadFile') { + // Handler for tool: uploadFile + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/pet/{petId}/uploadImage'; + const petId_val = validatedArgs['petId']; + if (typeof petId_val !== 'undefined' && petId_val !== null) { + urlPath = urlPath.replace('{petId}', encodeURIComponent(String(petId_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + const additionalMetadata_val = validatedArgs['additionalMetadata']; + if (typeof additionalMetadata_val !== 'undefined' && additionalMetadata_val !== null) + queryParams['additionalMetadata'] = additionalMetadata_val; + + const headers: Record = { Accept: 'application/json' }; + // Set Content-Type based on OpenAPI spec (or fallback) + if (typeof validatedArgs?.['requestBody'] !== 'undefined') { + headers['content-type'] = 'application/octet-stream'; + } + + let requestBodyData: any = undefined; + if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { + requestBodyData = validatedArgs['requestBody']; + } + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'POST', + url: requestUrl, + params: queryParams, + headers: headers, + data: requestBodyData, // Pass the prepared request body data // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'getInventory') { + // Handler for tool: getInventory + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/store/inventory'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'placeOrder') { + // Handler for tool: placeOrder + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/store/order'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + // Set Content-Type based on OpenAPI spec (or fallback) + if (typeof validatedArgs?.['requestBody'] !== 'undefined') { + headers['content-type'] = 'application/json'; + } + + let requestBodyData: any = undefined; + if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { + requestBodyData = validatedArgs['requestBody']; + } + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'POST', + url: requestUrl, + params: queryParams, + headers: headers, + data: requestBodyData, // Pass the prepared request body data // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'getOrderById') { + // Handler for tool: getOrderById + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/store/order/{orderId}'; + const orderId_val = validatedArgs['orderId']; + if (typeof orderId_val !== 'undefined' && orderId_val !== null) { + urlPath = urlPath.replace('{orderId}', encodeURIComponent(String(orderId_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'deleteOrder') { + // Handler for tool: deleteOrder + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/store/order/{orderId}'; + const orderId_val = validatedArgs['orderId']; + if (typeof orderId_val !== 'undefined' && orderId_val !== null) { + urlPath = urlPath.replace('{orderId}', encodeURIComponent(String(orderId_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'DELETE', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'createUser') { + // Handler for tool: createUser + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/user'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + // Set Content-Type based on OpenAPI spec (or fallback) + if (typeof validatedArgs?.['requestBody'] !== 'undefined') { + headers['content-type'] = 'application/json'; + } + + let requestBodyData: any = undefined; + if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { + requestBodyData = validatedArgs['requestBody']; + } + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'POST', + url: requestUrl, + params: queryParams, + headers: headers, + data: requestBodyData, // Pass the prepared request body data // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'createUsersWithListInput') { + // Handler for tool: createUsersWithListInput + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/user/createWithList'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + // Set Content-Type based on OpenAPI spec (or fallback) + if (typeof validatedArgs?.['requestBody'] !== 'undefined') { + headers['content-type'] = 'application/json'; + } + + let requestBodyData: any = undefined; + if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { + requestBodyData = validatedArgs['requestBody']; + } + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'POST', + url: requestUrl, + params: queryParams, + headers: headers, + data: requestBodyData, // Pass the prepared request body data // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'loginUser') { + // Handler for tool: loginUser + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/user/login'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + const username_val = validatedArgs['username']; + if (typeof username_val !== 'undefined' && username_val !== null) + queryParams['username'] = username_val; + const password_val = validatedArgs['password']; + if (typeof password_val !== 'undefined' && password_val !== null) + queryParams['password'] = password_val; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'logoutUser') { + // Handler for tool: logoutUser + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/user/logout'; + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'getUserByName') { + // Handler for tool: getUserByName + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/user/{username}'; + const username_val = validatedArgs['username']; + if (typeof username_val !== 'undefined' && username_val !== null) { + urlPath = urlPath.replace('{username}', encodeURIComponent(String(username_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'GET', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'updateUser') { + // Handler for tool: updateUser + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/user/{username}'; + const username_val = validatedArgs['username']; + if (typeof username_val !== 'undefined' && username_val !== null) { + urlPath = urlPath.replace('{username}', encodeURIComponent(String(username_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + // Set Content-Type based on OpenAPI spec (or fallback) + if (typeof validatedArgs?.['requestBody'] !== 'undefined') { + headers['content-type'] = 'application/json'; + } + + let requestBodyData: any = undefined; + if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { + requestBodyData = validatedArgs['requestBody']; + } + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'PUT', + url: requestUrl, + params: queryParams, + headers: headers, + data: requestBodyData, // Pass the prepared request body data // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } else if (toolName === 'deleteUser') { + // Handler for tool: deleteUser + try { + // --- Argument Validation using Zod --- + let validatedArgs: JsonObject; + try { + const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); + const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; + validatedArgs = zodSchema.parse(argsToParse); + console.error(`Arguments validated successfully for tool '${toolName}'.`); + } catch (error: any) { + if (error instanceof ZodError) { + const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; + console.error(validationErrorMessage); + return { content: [{ type: 'text', text: validationErrorMessage }] }; + } else { + console.error( + `Unexpected error during argument validation setup for tool '${toolName}':`, + error + ); + return { + content: [ + { + type: 'text', + text: `Internal server error during argument validation setup for tool '${toolName}'.`, + }, + ], + }; + } + } + // --- End Argument Validation --- + + // --- API Call Preparation --- + let urlPath = '/user/{username}'; + const username_val = validatedArgs['username']; + if (typeof username_val !== 'undefined' && username_val !== null) { + urlPath = urlPath.replace('{username}', encodeURIComponent(String(username_val))); + } + if (urlPath.includes('{')) { + throw new Error( + `Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.` + ); + } + const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; + const queryParams: Record = {}; + + const headers: Record = { Accept: 'application/json' }; + + // Declare and assign requestBodyData *here* + + // --- Axios Request Configuration --- + // Now 'requestBodyData' is declared before being referenced here + const config: AxiosRequestConfig = { + method: 'DELETE', + url: requestUrl, + params: queryParams, + headers: headers, + // Include data property conditionally + // Add Authentication logic here if needed + }; + + console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); + + // --- Execute API Call --- + const response = await axios(config); + + // --- Process Successful Response --- + let responseText = ''; + const contentType = response.headers['content-type']?.toLowerCase() || ''; + if ( + contentType.includes('application/json') && + typeof response.data === 'object' && + response.data !== null + ) { + try { + responseText = JSON.stringify(response.data, null, 2); + } catch (e) { + responseText = '[Error: Failed to stringify JSON response]'; + } + } else if (typeof response.data === 'string') { + responseText = response.data; + } else if (response.data !== undefined && response.data !== null) { + responseText = String(response.data); + } else { + responseText = `(Status: ${response.status} - No body content)`; + } + return { + content: [ + { type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }, + ], + }; + } catch (error: any) { + // --- Handle Errors (Post-Validation) --- + let errorMessage = `Error executing tool '${toolName}': ${error.message}`; + if (axios.isAxiosError(error)) { + errorMessage = formatApiError(error); + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = 'An unexpected error occurred: ' + String(error); + } + console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); + return { content: [{ type: 'text', text: errorMessage }] }; + } + } // This generated code now includes Zod validation + + // Fallback error + console.error( + `Error: Handler logic missing for tool: ${toolName}. This indicates an issue in the generator.` + ); + return { + content: [ + { + type: 'text', + text: `Error: Internal server error - handler not implemented for tool: ${toolName}`, + }, + ], + }; } - - // --- Tool Execution Logic --- - - // Handler for tool: updatePet - if (toolName === "updatePet") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - // Set Content-Type based on OpenAPI spec (or fallback) - if (typeof validatedArgs?.['requestBody'] !== 'undefined') { headers['content-type'] = 'application/json'; } - - let requestBodyData: any = undefined; - if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - } - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "PUT", - url: requestUrl, - params: queryParams, - headers: headers, - data: requestBodyData, // Pass the prepared request body data // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: addPet - if (toolName === "addPet") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - // Set Content-Type based on OpenAPI spec (or fallback) - if (typeof validatedArgs?.['requestBody'] !== 'undefined') { headers['content-type'] = 'application/json'; } - - let requestBodyData: any = undefined; - if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - } - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "POST", - url: requestUrl, - params: queryParams, - headers: headers, - data: requestBodyData, // Pass the prepared request body data // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: findPetsByStatus - if (toolName === "findPetsByStatus") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet/findByStatus"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - const status_val = validatedArgs['status']; - if (typeof status_val !== 'undefined' && status_val !== null) queryParams['status'] = status_val; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: findPetsByTags - if (toolName === "findPetsByTags") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet/findByTags"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - const tags_val = validatedArgs['tags']; - if (typeof tags_val !== 'undefined' && tags_val !== null) queryParams['tags'] = tags_val; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: getPetById - if (toolName === "getPetById") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet/{petId}"; - const petId_val = validatedArgs['petId']; - if (typeof petId_val !== 'undefined' && petId_val !== null) { urlPath = urlPath.replace("{petId}", encodeURIComponent(String(petId_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: updatePetWithForm - if (toolName === "updatePetWithForm") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet/{petId}"; - const petId_val = validatedArgs['petId']; - if (typeof petId_val !== 'undefined' && petId_val !== null) { urlPath = urlPath.replace("{petId}", encodeURIComponent(String(petId_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - const name_val = validatedArgs['name']; - if (typeof name_val !== 'undefined' && name_val !== null) queryParams['name'] = name_val; - const status_val = validatedArgs['status']; - if (typeof status_val !== 'undefined' && status_val !== null) queryParams['status'] = status_val; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "POST", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: deletePet - if (toolName === "deletePet") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet/{petId}"; - const petId_val = validatedArgs['petId']; - if (typeof petId_val !== 'undefined' && petId_val !== null) { urlPath = urlPath.replace("{petId}", encodeURIComponent(String(petId_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - const api_key_val = validatedArgs['api_key']; - if (typeof api_key_val !== 'undefined' && api_key_val !== null) headers['api_key'] = String(api_key_val); - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "DELETE", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: uploadFile - if (toolName === "uploadFile") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/pet/{petId}/uploadImage"; - const petId_val = validatedArgs['petId']; - if (typeof petId_val !== 'undefined' && petId_val !== null) { urlPath = urlPath.replace("{petId}", encodeURIComponent(String(petId_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - const additionalMetadata_val = validatedArgs['additionalMetadata']; - if (typeof additionalMetadata_val !== 'undefined' && additionalMetadata_val !== null) queryParams['additionalMetadata'] = additionalMetadata_val; - - const headers: Record = { 'Accept': 'application/json' }; - // Set Content-Type based on OpenAPI spec (or fallback) - if (typeof validatedArgs?.['requestBody'] !== 'undefined') { headers['content-type'] = 'application/octet-stream'; } - - let requestBodyData: any = undefined; - if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - } - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "POST", - url: requestUrl, - params: queryParams, - headers: headers, - data: requestBodyData, // Pass the prepared request body data // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: getInventory - if (toolName === "getInventory") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/store/inventory"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: placeOrder - if (toolName === "placeOrder") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/store/order"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - // Set Content-Type based on OpenAPI spec (or fallback) - if (typeof validatedArgs?.['requestBody'] !== 'undefined') { headers['content-type'] = 'application/json'; } - - let requestBodyData: any = undefined; - if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - } - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "POST", - url: requestUrl, - params: queryParams, - headers: headers, - data: requestBodyData, // Pass the prepared request body data // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: getOrderById - if (toolName === "getOrderById") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/store/order/{orderId}"; - const orderId_val = validatedArgs['orderId']; - if (typeof orderId_val !== 'undefined' && orderId_val !== null) { urlPath = urlPath.replace("{orderId}", encodeURIComponent(String(orderId_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: deleteOrder - if (toolName === "deleteOrder") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/store/order/{orderId}"; - const orderId_val = validatedArgs['orderId']; - if (typeof orderId_val !== 'undefined' && orderId_val !== null) { urlPath = urlPath.replace("{orderId}", encodeURIComponent(String(orderId_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "DELETE", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: createUser - if (toolName === "createUser") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/user"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - // Set Content-Type based on OpenAPI spec (or fallback) - if (typeof validatedArgs?.['requestBody'] !== 'undefined') { headers['content-type'] = 'application/json'; } - - let requestBodyData: any = undefined; - if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - } - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "POST", - url: requestUrl, - params: queryParams, - headers: headers, - data: requestBodyData, // Pass the prepared request body data // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: createUsersWithListInput - if (toolName === "createUsersWithListInput") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/user/createWithList"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - // Set Content-Type based on OpenAPI spec (or fallback) - if (typeof validatedArgs?.['requestBody'] !== 'undefined') { headers['content-type'] = 'application/json'; } - - let requestBodyData: any = undefined; - if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - } - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "POST", - url: requestUrl, - params: queryParams, - headers: headers, - data: requestBodyData, // Pass the prepared request body data // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: loginUser - if (toolName === "loginUser") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/user/login"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - const username_val = validatedArgs['username']; - if (typeof username_val !== 'undefined' && username_val !== null) queryParams['username'] = username_val; - const password_val = validatedArgs['password']; - if (typeof password_val !== 'undefined' && password_val !== null) queryParams['password'] = password_val; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: logoutUser - if (toolName === "logoutUser") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/user/logout"; - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: getUserByName - if (toolName === "getUserByName") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/user/{username}"; - const username_val = validatedArgs['username']; - if (typeof username_val !== 'undefined' && username_val !== null) { urlPath = urlPath.replace("{username}", encodeURIComponent(String(username_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "GET", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: updateUser - if (toolName === "updateUser") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/user/{username}"; - const username_val = validatedArgs['username']; - if (typeof username_val !== 'undefined' && username_val !== null) { urlPath = urlPath.replace("{username}", encodeURIComponent(String(username_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - // Set Content-Type based on OpenAPI spec (or fallback) - if (typeof validatedArgs?.['requestBody'] !== 'undefined') { headers['content-type'] = 'application/json'; } - - let requestBodyData: any = undefined; - if (validatedArgs && typeof validatedArgs['requestBody'] !== 'undefined') { - requestBodyData = validatedArgs['requestBody']; - } - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "PUT", - url: requestUrl, - params: queryParams, - headers: headers, - data: requestBodyData, // Pass the prepared request body data // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } else - // Handler for tool: deleteUser - if (toolName === "deleteUser") { - try { - - // --- Argument Validation using Zod --- - let validatedArgs: JsonObject; - try { - const zodSchema = getZodSchemaFromJsonSchema(toolDefinition.inputSchema, toolName); - const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {}; - validatedArgs = zodSchema.parse(argsToParse); - console.error(`Arguments validated successfully for tool '${toolName}'.`); - } catch (error: any) { - if (error instanceof ZodError) { - const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors.map(e => `${e.path.join('.')} (${e.code}): ${e.message}`).join(', ')}`; - console.error(validationErrorMessage); - return { content: [{ type: 'text', text: validationErrorMessage }] }; - } else { - console.error(`Unexpected error during argument validation setup for tool '${toolName}':`, error); - return { content: [{ type: 'text', text: `Internal server error during argument validation setup for tool '${toolName}'.` }] }; - } - } - // --- End Argument Validation --- - - // --- API Call Preparation --- - let urlPath = "/user/{username}"; - const username_val = validatedArgs['username']; - if (typeof username_val !== 'undefined' && username_val !== null) { urlPath = urlPath.replace("{username}", encodeURIComponent(String(username_val))); } - if (urlPath.includes('{')) { throw new Error(`Validation passed but failed to resolve path parameters in URL: ${urlPath}. Check schema/validation logic.`); } - const requestUrl = API_BASE_URL ? `${API_BASE_URL}${urlPath}` : urlPath; - const queryParams: Record = {}; - - const headers: Record = { 'Accept': 'application/json' }; - - // Declare and assign requestBodyData *here* - - // --- Axios Request Configuration --- - // Now 'requestBodyData' is declared before being referenced here - const config: AxiosRequestConfig = { - method: "DELETE", - url: requestUrl, - params: queryParams, - headers: headers, - // Include data property conditionally - // Add Authentication logic here if needed - }; - - console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`); - - // --- Execute API Call --- - const response = await axios(config); - - // --- Process Successful Response --- - let responseText = ''; - const contentType = response.headers['content-type']?.toLowerCase() || ''; - if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) { - try { responseText = JSON.stringify(response.data, null, 2); } - catch (e) { responseText = "[Error: Failed to stringify JSON response]"; } - } else if (typeof response.data === 'string') { - responseText = response.data; - } else if (response.data !== undefined && response.data !== null) { - responseText = String(response.data); - } else { - responseText = `(Status: ${response.status} - No body content)`; - } - return { content: [ { type: "text", text: `API Response (Status: ${response.status}):\n${responseText}` } ], }; - - } catch (error: any) { - // --- Handle Errors (Post-Validation) --- - let errorMessage = `Error executing tool '${toolName}': ${error.message}`; - if (axios.isAxiosError(error)) { errorMessage = formatApiError(error); } - else if (error instanceof Error) { errorMessage = error.message; } - else { errorMessage = 'An unexpected error occurred: ' + String(error); } - console.error(`Error during execution of tool '${toolName}':`, errorMessage, error.stack); - return { content: [{ type: "text", text: errorMessage }] }; - } - } // This generated code now includes Zod validation - - // Fallback error - console.error(`Error: Handler logic missing for tool: ${toolName}. This indicates an issue in the generator.`); - return { content: [{ type: "text", text: `Error: Internal server error - handler not implemented for tool: ${toolName}` }] }; -}); - +); // --- Main Execution Function --- async function main() { try { const transport = new StdioServerTransport(); await server.connect(transport); - console.error(`${SERVER_NAME} MCP Server (v${SERVER_VERSION}) running on stdio${API_BASE_URL ? `, proxying API at ${API_BASE_URL}` : ''}`); + console.error( + `${SERVER_NAME} MCP Server (v${SERVER_VERSION}) running on stdio${API_BASE_URL ? `, proxying API at ${API_BASE_URL}` : ''}` + ); } catch (error) { - console.error("Error during server startup:", error); + console.error('Error during server startup:', error); process.exit(1); } } // --- Cleanup Function --- async function cleanup() { - console.error("Shutting down MCP server..."); - process.exit(0); + console.error('Shutting down MCP server...'); + process.exit(0); } // Register signal handlers @@ -2146,36 +2646,37 @@ process.on('SIGTERM', cleanup); // --- Start the Server --- main().catch((error) => { - console.error("Fatal error in main execution:", error); + console.error('Fatal error in main execution:', error); process.exit(1); }); // --- Helper Functions (Included in the generated server code) --- function formatApiError(error: AxiosError): string { - let message = 'API request failed.'; - if (error.response) { - message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `; - const responseData = error.response.data; - const MAX_LEN = 200; - if (typeof responseData === 'string') { - message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`; - } else if (responseData) { - try { - const jsonString = JSON.stringify(responseData); - message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`; - } catch { - message += 'Response: [Could not serialize response data]'; - } - } else { - message += 'No response body received.'; - } - } else if (error.request) { - message = 'API Network Error: No response received from the server. Check network connectivity or server availability.'; - if (error.code) message += ` (Code: ${error.code})`; + let message = 'API request failed.'; + if (error.response) { + message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `; + const responseData = error.response.data; + const MAX_LEN = 200; + if (typeof responseData === 'string') { + message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`; + } else if (responseData) { + try { + const jsonString = JSON.stringify(responseData); + message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`; + } catch { + message += 'Response: [Could not serialize response data]'; + } } else { - message = `API Request Setup Error: ${error.message}`; + message += 'No response body received.'; } - return message; + } else if (error.request) { + message = + 'API Network Error: No response received from the server. Check network connectivity or server availability.'; + if (error.code) message += ` (Code: ${error.code})`; + } else { + message = `API Request Setup Error: ${error.message}`; + } + return message; } /** @@ -2188,32 +2689,34 @@ function formatApiError(error: AxiosError): string { * @throws If schema conversion or evaluation fails. */ function getZodSchemaFromJsonSchema(jsonSchema: any, toolName: string): z.ZodTypeAny { - if (typeof jsonSchema !== 'object' || jsonSchema === null) { - // Handle boolean schemas or invalid input - console.warn(`Cannot generate Zod schema for non-object JSON schema for tool '${toolName}'. Input type: ${typeof jsonSchema}`) - // Fallback to allowing any object - adjust if stricter handling is needed - return z.object({}).passthrough(); - } - try { - // Note: jsonSchemaToZod may require specific configurations or adjustments - // depending on the complexity of the JSON Schemas being converted. - const zodSchemaString = jsonSchemaToZod(jsonSchema); + if (typeof jsonSchema !== 'object' || jsonSchema === null) { + // Handle boolean schemas or invalid input + console.warn( + `Cannot generate Zod schema for non-object JSON schema for tool '${toolName}'. Input type: ${typeof jsonSchema}` + ); + // Fallback to allowing any object - adjust if stricter handling is needed + return z.object({}).passthrough(); + } + try { + // Note: jsonSchemaToZod may require specific configurations or adjustments + // depending on the complexity of the JSON Schemas being converted. + const zodSchemaString = jsonSchemaToZod(jsonSchema); - // IMPORTANT: Using eval() to execute the generated Zod schema string. - // This is generally discouraged due to security risks with untrusted input. - // Ensure the JSON schemas processed here are from trusted sources (like your OpenAPI spec). - // The 'z' variable (from imported zod) must be in scope for eval. - const zodSchema = eval(zodSchemaString); + // IMPORTANT: Using eval() to execute the generated Zod schema string. + // This is generally discouraged due to security risks with untrusted input. + // Ensure the JSON schemas processed here are from trusted sources (like your OpenAPI spec). + // The 'z' variable (from imported zod) must be in scope for eval. + const zodSchema = eval(zodSchemaString); - if (typeof zodSchema?.parse !== 'function') { - throw new Error('Generated Zod schema string did not evaluate to a valid Zod schema object.'); - } - return zodSchema as z.ZodTypeAny; - } catch (err: any) { - console.error(`Failed to generate or evaluate Zod schema for tool '${toolName}':`, err); - // Fallback schema in case of conversion/evaluation error - // This allows any object, effectively skipping validation on error. - // Consider throwing the error if validation is critical. - return z.object({}).passthrough(); + if (typeof zodSchema?.parse !== 'function') { + throw new Error('Generated Zod schema string did not evaluate to a valid Zod schema object.'); } + return zodSchema as z.ZodTypeAny; + } catch (err: any) { + console.error(`Failed to generate or evaluate Zod schema for tool '${toolName}':`, err); + // Fallback schema in case of conversion/evaluation error + // This allows any object, effectively skipping validation on error. + // Consider throwing the error if validation is critical. + return z.object({}).passthrough(); + } } diff --git a/examples/petstore-mcp/tsconfig.json b/examples/petstore-mcp/tsconfig.json index e4cecf3..3ee07ce 100644 --- a/examples/petstore-mcp/tsconfig.json +++ b/examples/petstore-mcp/tsconfig.json @@ -17,11 +17,6 @@ "sourceMap": true, "forceConsistentCasingInFileNames": true }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "build" - ] -} \ No newline at end of file + "include": ["src/**/*"], + "exclude": ["node_modules", "build"] +} diff --git a/package-lock.json b/package-lock.json index 183362a..3ea9773 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,3206 +1,3206 @@ { - "name": "openapi-mcp-generator", - "version": "3.1.2", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "openapi-mcp-generator", - "version": "3.1.2", - "license": "MIT", - "dependencies": { - "@apidevtools/swagger-parser": "^10.1.1", - "commander": "^13.1.0", - "openapi-types": "^12.1.3" - }, - "bin": { - "openapi-mcp-generator": "bin/openapi-mcp-generator.js" - }, - "devDependencies": { - "@types/node": "^22.15.2", - "@typescript-eslint/eslint-plugin": "^8.31.0", - "@typescript-eslint/parser": "^8.31.0", - "eslint": "^9.25.1", - "prettier": "^3.5.3", - "rimraf": "^6.0.1", - "typescript": "^5.8.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@modelcontextprotocol/sdk": "^1.10.0", - "json-schema-to-zod": "^2.6.1", - "zod": "^3.24.3" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz", - "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", - "license": "MIT", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, - "node_modules/@apidevtools/openapi-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/@apidevtools/swagger-methods": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", - "license": "MIT" - }, - "node_modules/@apidevtools/swagger-parser": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.1.tgz", - "integrity": "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==", - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "11.7.2", - "@apidevtools/openapi-schemas": "^2.1.0", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "call-me-maybe": "^1.0.2" - }, - "peerDependencies": { - "openapi-types": ">=7" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz", - "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", - "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "license": "MIT" - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.10.2.tgz", - "integrity": "sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==", - "license": "MIT", - "peer": true, - "dependencies": { - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.3", - "eventsource": "^3.0.2", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.15.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.2.tgz", - "integrity": "sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz", - "integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/type-utils": "8.31.0", - "@typescript-eslint/utils": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz", - "integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz", - "integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz", - "integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/utils": "8.31.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz", - "integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz", - "integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz", - "integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz", - "integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.31.0", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "peer": true, - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "license": "MIT", - "peerDependencies": { - "ajv": "^8.5.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", - "license": "MIT", - "peer": true, - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", - "license": "MIT" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "peer": true, - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT", - "peer": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "peer": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT", - "peer": true - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", - "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.6.tgz", - "integrity": "sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==", - "license": "MIT", - "peer": true, - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz", - "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "license": "MIT", - "peer": true, - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", - "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": "^4.11 || 5 || ^5.0.0-beta.1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "peer": true, - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", - "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC", - "peer": true - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT", - "peer": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", - "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-to-zod": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/json-schema-to-zod/-/json-schema-to-zod-2.6.1.tgz", - "integrity": "sha512-uiHmWH21h9FjKJkRBntfVGTLpYlCZ1n98D0izIlByqQLqpmkQpNTBtfbdP04Na6+43lgsvrShFh2uWLkQDKJuQ==", - "license": "ISC", - "peer": true, - "bin": { - "json-schema-to-zod": "dist/cjs/cli.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", - "peer": true, - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "peer": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "peer": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/openapi-types": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", - "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", - "license": "MIT" - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "peer": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", - "license": "MIT", - "peer": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", - "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^11.0.0", - "package-json-from-dist": "^1.0.0" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT", - "peer": true - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC", - "peer": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "peer": true, - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "peer": true, - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "peer": true, - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC", - "peer": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", - "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", - "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", - "license": "ISC", - "peer": true, - "peerDependencies": { - "zod": "^3.24.1" - } + "name": "openapi-mcp-generator", + "version": "3.1.2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openapi-mcp-generator", + "version": "3.1.2", + "license": "MIT", + "dependencies": { + "@apidevtools/swagger-parser": "^10.1.1", + "commander": "^13.1.0", + "openapi-types": "^12.1.3" + }, + "bin": { + "openapi-mcp-generator": "bin/openapi-mcp-generator.js" + }, + "devDependencies": { + "@types/node": "^22.15.2", + "@typescript-eslint/eslint-plugin": "^8.31.0", + "@typescript-eslint/parser": "^8.31.0", + "eslint": "^9.25.1", + "prettier": "^3.5.3", + "rimraf": "^6.0.1", + "typescript": "^5.8.3" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.10.0", + "json-schema-to-zod": "^2.6.1", + "zod": "^3.24.3" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz", + "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "license": "MIT" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.1.tgz", + "integrity": "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==", + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "11.7.2", + "@apidevtools/openapi-schemas": "^2.1.0", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "call-me-maybe": "^1.0.2" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz", + "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", + "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.10.2.tgz", + "integrity": "sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==", + "license": "MIT", + "peer": true, + "dependencies": { + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.3", + "eventsource": "^3.0.2", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.15.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.2.tgz", + "integrity": "sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz", + "integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.31.0", + "@typescript-eslint/type-utils": "8.31.0", + "@typescript-eslint/utils": "8.31.0", + "@typescript-eslint/visitor-keys": "8.31.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz", + "integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.31.0", + "@typescript-eslint/types": "8.31.0", + "@typescript-eslint/typescript-estree": "8.31.0", + "@typescript-eslint/visitor-keys": "8.31.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz", + "integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.0", + "@typescript-eslint/visitor-keys": "8.31.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz", + "integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.31.0", + "@typescript-eslint/utils": "8.31.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz", + "integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz", + "integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.0", + "@typescript-eslint/visitor-keys": "8.31.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz", + "integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.31.0", + "@typescript-eslint/types": "8.31.0", + "@typescript-eslint/typescript-estree": "8.31.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz", + "integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true } + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "peer": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT", + "peer": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT", + "peer": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", + "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.13.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.25.1", + "@eslint/plugin-kit": "^0.2.8", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.6.tgz", + "integrity": "sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==", + "license": "MIT", + "peer": true, + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz", + "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", + "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": "^4.11 || 5 || ^5.0.0-beta.1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "peer": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", + "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC", + "peer": true + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT", + "peer": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", + "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-to-zod": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/json-schema-to-zod/-/json-schema-to-zod-2.6.1.tgz", + "integrity": "sha512-uiHmWH21h9FjKJkRBntfVGTLpYlCZ1n98D0izIlByqQLqpmkQpNTBtfbdP04Na6+43lgsvrShFh2uWLkQDKJuQ==", + "license": "ISC", + "peer": true, + "bin": { + "json-schema-to-zod": "dist/cjs/cli.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "peer": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT", + "peer": true + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC", + "peer": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "peer": true, + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC", + "peer": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.24.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", + "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", + "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", + "license": "ISC", + "peer": true, + "peerDependencies": { + "zod": "^3.24.1" + } } + } } diff --git a/package.json b/package.json index 68edd75..1b1a92a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "scripts": { "start": "node dist/index.js", "clean": "rimraf dist", + "format.check": "prettier --check .", + "format.write": "prettier --write .", "typecheck": "tsc --noEmit", "build": "tsc && chmod 755 dist/index.js && chmod 755 bin/openapi-mcp-generator.js", "version:patch": "npm version patch", diff --git a/src/api.ts b/src/api.ts index c884687..7194000 100644 --- a/src/api.ts +++ b/src/api.ts @@ -15,20 +15,20 @@ import { determineBaseUrl } from './utils/url.js'; export interface GetToolsOptions { /** Optional base URL to override the one in the OpenAPI spec */ baseUrl?: string; - + /** Whether to dereference the OpenAPI spec */ dereference?: boolean; - + /** Array of operation IDs to exclude from the tools list */ excludeOperationIds?: string[]; - + /** Optional filter function to exclude tools based on custom criteria */ filterFn?: (tool: McpToolDefinition) => boolean; } /** * Get a list of tools from an OpenAPI specification - * + * * @param specPathOrUrl Path or URL to the OpenAPI specification * @param options Options for generating the tools * @returns Promise that resolves to an array of tool definitions @@ -39,32 +39,32 @@ export async function getToolsFromOpenApi( ): Promise { try { // Parse the OpenAPI spec - const api = options.dereference - ? (await SwaggerParser.dereference(specPathOrUrl)) as OpenAPIV3.Document - : (await SwaggerParser.parse(specPathOrUrl)) as OpenAPIV3.Document; + const api = options.dereference + ? ((await SwaggerParser.dereference(specPathOrUrl)) as OpenAPIV3.Document) + : ((await SwaggerParser.parse(specPathOrUrl)) as OpenAPIV3.Document); // Extract tools from the API const allTools = extractToolsFromApi(api); - + // Add base URL to each tool const baseUrl = determineBaseUrl(api, options.baseUrl); - + // Apply filters to exclude specified operationIds and custom filter function let filteredTools = allTools; - + // Filter by excluded operation IDs if provided if (options.excludeOperationIds && options.excludeOperationIds.length > 0) { const excludeSet = new Set(options.excludeOperationIds); - filteredTools = filteredTools.filter(tool => !excludeSet.has(tool.operationId)); + filteredTools = filteredTools.filter((tool) => !excludeSet.has(tool.operationId)); } - + // Apply custom filter function if provided if (options.filterFn) { filteredTools = filteredTools.filter(options.filterFn); } - + // Return the filtered tools with base URL added - return filteredTools.map(tool => ({ + return filteredTools.map((tool) => ({ ...tool, baseUrl: baseUrl || '', })); @@ -78,4 +78,4 @@ export async function getToolsFromOpenApi( } // Export types for convenience -export { McpToolDefinition }; \ No newline at end of file +export { McpToolDefinition }; diff --git a/src/generator/streamable-http.ts b/src/generator/streamable-http.ts index b773a2a..7cc8d8e 100644 --- a/src/generator/streamable-http.ts +++ b/src/generator/streamable-http.ts @@ -1,4 +1,3 @@ - /** * Generator for StreamableHTTP server code for the MCP server using Hono */ diff --git a/tsconfig.json b/tsconfig.json index 6ab61fa..9fba5e2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,18 @@ { - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "declaration": true, - "sourceMap": true, - "outDir": "./dist", - "rootDir": "./src", - "resolveJsonModule": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "test"] - } \ No newline at end of file + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "declaration": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +}