diff --git a/.gitignore b/.gitignore index 112c4e8..c904b65 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ Desktop.ini *.tsv *.jsonl : + +# Ignore build output +dist/ \ No newline at end of file diff --git a/README.md b/README.md index b2c854c..e56501d 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,27 @@ Please refer to the official [DeepWiki page](https://deepwiki.com/ppl-ai/modelco ## Tools - **perplexity_ask** - - Engage in a conversation with the Sonar API for live web searches. + - Engages in a conversation using the Sonar API. - **Inputs:** - `messages` (array): An array of conversation messages. - Each message must include: - `role` (string): The role of the message (e.g., `system`, `user`, `assistant`). - `content` (string): The content of the message. + - `model` (string, optional): The model to use for the completion. Can be `sonar` or `sonar-pro`. Defaults to `sonar-pro`. + - `search_domain_filter` (array of strings, optional): A list of domains to limit search results to (max 10). To denylist a domain, prefix it with a `-`. + +- **perplexity_research** + - Performs deep research using the Perplexity API. + - **Inputs:** + - `messages` (array): An array of conversation messages. + - `search_domain_filter` (array of strings, optional): A list of domains to limit search results to (max 10). To denylist a domain, prefix it with a `-`. + +- **perplexity_reason** + - Performs reasoning tasks using the Perplexity API. + - **Inputs:** + - `messages` (array): An array of conversation messages. + - `model` (string, optional): The model to use for reasoning. Can be `sonar-reasoning` or `sonar-reasoning-pro`. Defaults to `sonar-reasoning-pro`. + - `search_domain_filter` (array of strings, optional): A list of domains to limit search results to (max 10). To denylist a domain, prefix it with a `-`. ## Configuration @@ -49,7 +64,21 @@ cd modelcontextprotocol/perplexity-ask && npm install 2. Follow the account setup instructions and generate your API key from the developer dashboard. 3. Set the API key in your environment as `PERPLEXITY_API_KEY`. -### Step 3: Configure Claude Desktop +### Step 3: Domain Filtering (Optional) + +You can control the domains that Perplexity searches by using the `search_domain_filter` parameter. The configuration follows this hierarchy: + +1. **User Input**: Provided directly in the tool call. +2. **Environment Variable**: If no user input is provided, the server will use the `PERPLEXITY_SEARCH_DOMAIN_FILTER` environment variable. +3. **Default**: If neither of the above is set, no domain filter will be applied. + +To set the environment variable, you can add it to your shell configuration (e.g., `.zshrc`, `.bashrc`) or a `.env` file: + +```bash +export PERPLEXITY_SEARCH_DOMAIN_FILTER="github.com,docs.pm,wikipedia.org" +``` + +### Step 4: Configure Claude Desktop 1. Download Claude desktop [here](https://claude.ai/download). diff --git a/perplexity-ask/index.ts b/perplexity-ask/index.ts index f5e5d6d..adf9f0c 100644 --- a/perplexity-ask/index.ts +++ b/perplexity-ask/index.ts @@ -40,6 +40,20 @@ const PERPLEXITY_ASK_TOOL: Tool = { }, description: "Array of conversation messages", }, + model: { + type: "string", + description: + "The model to use for the completion. Can be 'sonar' or 'sonar-pro'. Defaults to 'sonar-pro'.", + enum: ["sonar", "sonar-pro"], + }, + search_domain_filter: { + type: "array", + items: { + type: "string", + }, + description: + "A list of domains to limit search results to. Max 10. Add a - at the beginning of the domain string for denylisting.", + }, }, required: ["messages"], }, @@ -76,6 +90,14 @@ const PERPLEXITY_RESEARCH_TOOL: Tool = { }, description: "Array of conversation messages", }, + search_domain_filter: { + type: "array", + items: { + type: "string", + }, + description: + "A list of domains to limit search results to. Max 10. Add a - at the beginning of the domain string for denylisting.", + }, }, required: ["messages"], }, @@ -112,6 +134,20 @@ const PERPLEXITY_REASON_TOOL: Tool = { }, description: "Array of conversation messages", }, + model: { + type: "string", + description: + "The model to use for reasoning. Can be 'sonar-reasoning' or 'sonar-reasoning-pro'. Defaults to 'sonar-reasoning-pro'.", + enum: ["sonar-reasoning", "sonar-reasoning-pro"], + }, + search_domain_filter: { + type: "array", + items: { + type: "string", + }, + description: + "A list of domains to limit search results to. Max 10. Add a - at the beginning of the domain string for denylisting.", + }, }, required: ["messages"], }, @@ -123,6 +159,7 @@ if (!PERPLEXITY_API_KEY) { console.error("Error: PERPLEXITY_API_KEY environment variable is required"); process.exit(1); } +const DOMAIN_FILTER_ENV = process.env.PERPLEXITY_SEARCH_DOMAIN_FILTER; /** * Performs a chat completion by sending a request to the Perplexity API. @@ -135,18 +172,23 @@ if (!PERPLEXITY_API_KEY) { */ async function performChatCompletion( messages: Array<{ role: string; content: string }>, - model: string = "sonar-pro" + model: string = "sonar-pro", + search_domain_filter?: string[] ): Promise { // Construct the API endpoint URL and request body const url = new URL("https://api.perplexity.ai/chat/completions"); - const body = { + const body: any = { model: model, // Model identifier passed as parameter messages: messages, - // Additional parameters can be added here if required (e.g., max_tokens, temperature, etc.) - // See the Sonar API documentation for more details: - // https://docs.perplexity.ai/api-reference/chat-completions }; + if (search_domain_filter && search_domain_filter.length > 0) { + if (search_domain_filter.length > 10) { + throw new Error("search_domain_filter cannot contain more than 10 domains."); + } + body.search_domain_filter = search_domain_filter; + } + let response; try { response = await fetch(url.toString(), { @@ -182,7 +224,7 @@ async function performChatCompletion( throw new Error(`Failed to parse JSON response from Perplexity API: ${jsonError}`); } - // Directly retrieve the main message content from the response + // Directly retrieve the main message content from the response let messageContent = data.choices[0].message.content; // If citations are provided, append them to the message content @@ -230,14 +272,44 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { if (!args) { throw new Error("No arguments provided"); } + + let search_domain_filter = args.search_domain_filter as (string[] | undefined); + + // Hierarchy: user input > environment variable > default + if (search_domain_filter === undefined) { + if (DOMAIN_FILTER_ENV) { + search_domain_filter = DOMAIN_FILTER_ENV.split(',').map(d => d.trim()); + } else { + search_domain_filter = []; + } + } + + if (search_domain_filter && (!Array.isArray(search_domain_filter) || !search_domain_filter.every(item => typeof item === 'string'))) { + throw new Error(`Invalid arguments for ${name}: search_domain_filter must be an array of strings`); + } + switch (name) { case "perplexity_ask": { if (!Array.isArray(args.messages)) { - throw new Error("Invalid arguments for perplexity_ask: 'messages' must be an array"); + throw new Error( + "Invalid arguments for perplexity_ask: 'messages' must be an array" + ); } - // Invoke the chat completion function with the provided messages const messages = args.messages; - const result = await performChatCompletion(messages, "sonar-pro"); + const model = args.model ?? "sonar-pro"; + if ( + typeof model !== "string" || + !["sonar", "sonar-pro"].includes(model) + ) { + throw new Error( + "Invalid model for perplexity_ask. Must be 'sonar' or 'sonar-pro'." + ); + } + const result = await performChatCompletion( + messages, + model, + search_domain_filter + ); return { content: [{ type: "text", text: result }], isError: false, @@ -245,11 +317,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { } case "perplexity_research": { if (!Array.isArray(args.messages)) { - throw new Error("Invalid arguments for perplexity_research: 'messages' must be an array"); + throw new Error( + "Invalid arguments for perplexity_research: 'messages' must be an array" + ); } // Invoke the chat completion function with the provided messages using the deep research model const messages = args.messages; - const result = await performChatCompletion(messages, "sonar-deep-research"); + const result = await performChatCompletion( + messages, + "sonar-deep-research", + search_domain_filter + ); return { content: [{ type: "text", text: result }], isError: false, @@ -257,11 +335,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { } case "perplexity_reason": { if (!Array.isArray(args.messages)) { - throw new Error("Invalid arguments for perplexity_reason: 'messages' must be an array"); + throw new Error( + "Invalid arguments for perplexity_reason: 'messages' must be an array" + ); } - // Invoke the chat completion function with the provided messages using the reasoning model const messages = args.messages; - const result = await performChatCompletion(messages, "sonar-reasoning-pro"); + const model = args.model ?? "sonar-reasoning-pro"; + if ( + typeof model !== "string" || + !["sonar-reasoning", "sonar-reasoning-pro"].includes(model) + ) { + throw new Error( + "Invalid model for perplexity_reason. Must be 'sonar-reasoning' or 'sonar-reasoning-pro'." + ); + } + const result = await performChatCompletion( + messages, + model, + search_domain_filter + ); return { content: [{ type: "text", text: result }], isError: false, @@ -280,7 +372,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { content: [ { type: "text", - text: `Error: ${error instanceof Error ? error.message : String(error)}`, + text: `Error: ${ + error instanceof Error ? error.message : String(error) + }`, }, ], isError: true, diff --git a/perplexity-ask/package-lock.json b/perplexity-ask/package-lock.json index f8e1c2d..17c9fd5 100644 --- a/perplexity-ask/package-lock.json +++ b/perplexity-ask/package-lock.json @@ -1,23 +1,28 @@ { - "name": "@modelcontextprotocol/server-perplexity-ask", + "name": "server-perplexity-ask", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@modelcontextprotocol/server-perplexity-ask", + "name": "server-perplexity-ask", "version": "0.1.0", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.1" + "@modelcontextprotocol/sdk": "^1.0.1", + "axios": "^1.6.2", + "dotenv": "^16.3.1" }, "bin": { "mcp-server-perplexity-ask": "dist/index.js" }, "devDependencies": { - "@types/node": "^22", + "@types/node": "^20", "shx": "^0.3.4", "typescript": "^5.6.2" + }, + "engines": { + "node": ">=18" } }, "node_modules/@modelcontextprotocol/sdk": { @@ -32,13 +37,30 @@ } }, "node_modules/@types/node": { - "version": "22.13.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz", - "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==", + "version": "20.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz", + "integrity": "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~6.21.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/balanced-match": { @@ -68,6 +90,31 @@ "node": ">= 0.8" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -84,6 +131,15 @@ "node": ">= 0.6" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -93,6 +149,113 @@ "node": ">= 0.8" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -104,12 +267,48 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "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", + "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", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -132,11 +331,49 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -217,6 +454,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -267,6 +534,12 @@ "dev": true, "license": "MIT" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/raw-body": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", @@ -408,9 +681,9 @@ } }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "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" },