diff --git a/.actor/ACTOR.md b/.actor/ACTOR.md new file mode 100644 index 00000000..6d2c8417 --- /dev/null +++ b/.actor/ACTOR.md @@ -0,0 +1,506 @@ +# Apify Model Context Protocol (MCP) Server + +[![Actors MCP Server](https://apify.com/actor-badge?actor=apify/actors-mcp-server)](https://apify.com/apify/actors-mcp-server) +[![smithery badge](https://smithery.ai/badge/@apify/actors-mcp-server)](https://smithery.ai/server/@apify/actors-mcp-server) + +Implementation of an MCP server for all [Apify Actors](https://apify.com/store). +This server enables interaction with one or more Apify Actors that can be defined in the MCP Server configuration. + +The server can be used in two ways: +- **🇦 [MCP Server Actor](https://apify.com/apify/actors-mcp-server)** – HTTP server accessible via Server-Sent Events (SSE), see [guide](#-mcp-server-actor) +- **⾕ MCP Server Stdio** – Local server available via standard input/output (stdio), see [guide](#-mcp-server-at-a-local-host) + +You can also interact with the MCP server using a chat-like UI with 💬 [Tester MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) + +# 🎯 What does Apify MCP server do? + +The MCP Server Actor allows an AI assistant to use any [Apify Actor](https://apify.com/store) as a tool to perform a specific task. +For example, it can: +- Use [Facebook Posts Scraper](https://apify.com/apify/facebook-posts-scraper) to extract data from Facebook posts from multiple pages/profiles +- Use [Google Maps Email Extractor](https://apify.com/lukaskrivka/google-maps-with-contact-details) to extract Google Maps contact details +- Use [Google Search Results Scraper](https://apify.com/apify/google-search-scraper) to scrape Google Search Engine Results Pages (SERPs) +- Use [Instagram Scraper](https://apify.com/apify/instagram-scraper) to scrape Instagram posts, profiles, places, photos, and comments +- Use [RAG Web Browser](https://apify.com/apify/web-scraper) to search the web, scrape the top N URLs, and return their content + +# MCP Clients + +To interact with the Apify MCP server, you can use MCP clients such as: +- [Claude Desktop](https://claude.ai/download) (only Stdio support) +- [Visual Studio Code](https://code.visualstudio.com/) (Stdio and SSE support) +- [LibreChat](https://www.librechat.ai/) (Stdio and SSE support, yet without Authorization header) +- [Apify Tester MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) (SSE support with Authorization headers) +- Other clients at [https://modelcontextprotocol.io/clients](https://modelcontextprotocol.io/clients) +- More clients at [https://glama.ai/mcp/clients](https://glama.ai/mcp/clients) + +When you have Actors integrated with the MCP server, you can ask: +- "Search the web and summarize recent trends about AI Agents" +- "Find the top 10 best Italian restaurants in San Francisco" +- "Find and analyze the Instagram profile of The Rock" +- "Provide a step-by-step guide on using the Model Context Protocol with source URLs" +- "What Apify Actors can I use?" + +The following image shows how the Apify MCP server interacts with the Apify platform and AI clients: + +![Actors-MCP-server](https://raw.githubusercontent.com/apify/actors-mcp-server/refs/heads/master/docs/actors-mcp-server.png) + +With the MCP Tester client you can load Actors dynamically but this is not yet supported by other MCP clients. +We also plan to add more features, see [Roadmap](#-roadmap-march-2025) for more details. + +# 🔄 What is the Model Context Protocol? + +The Model Context Protocol (MCP) allows AI applications (and AI agents), such as Claude Desktop, to connect to external tools and data sources. +MCP is an open protocol that enables secure, controlled interactions between AI applications, AI Agents, and local or remote resources. + +For more information, see the [Model Context Protocol](https://modelcontextprotocol.org/) website or the blog post [What is MCP and why does it matter?](https://blog.apify.com/what-is-model-context-protocol/). + +# 🤖 How is MCP Server related to AI Agents? + +The Apify MCP Server exposes Apify's Actors through the MCP protocol, allowing AI Agents or frameworks that implement the MCP protocol to access all Apify Actors as tools for data extraction, web searching, and other tasks. + +To learn more about AI Agents, explore our blog post: [What are AI Agents?](https://blog.apify.com/what-are-ai-agents/) and browse Apify's curated [AI Agent collection](https://apify.com/store/collections/ai_agents). +Interested in building and monetizing your own AI agent on Apify? Check out our [step-by-step guide](https://blog.apify.com/how-to-build-an-ai-agent/) for creating, publishing, and monetizing AI agents on the Apify platform. + +# 🧱 Components + +## Tools + +### Actors + +Any [Apify Actor](https://apify.com/store) can be used as a tool. +By default, the server is pre-configured with the Actors specified below, but this can be overridden by providing Actor input. + +```text +'apify/instagram-scraper' +'apify/rag-web-browser' +'lukaskrivka/google-maps-with-contact-details' +``` +The MCP server loads the Actor input schema and creates MCP tools corresponding to the Actors. +See this example of input schema for the [RAG Web Browser](https://apify.com/apify/rag-web-browser/input-schema). + +The tool name must always be the full Actor name, such as `apify/rag-web-browser`. +The arguments for an MCP tool represent the input parameters of the Actor. +For example, for the `apify/rag-web-browser` Actor, the arguments are: + +```json +{ + "query": "restaurants in San Francisco", + "maxResults": 3 +} +``` +You don't need to specify the input parameters or which Actor to call; everything is managed by an LLM. +When a tool is called, the arguments are automatically passed to the Actor by the LLM. +You can refer to the specific Actor's documentation for a list of available arguments. + +### Helper tools + +The server provides a set of helper tools to discover available Actors and retrieve their details: +- `get-actor-details`: Retrieves documentation, input schema, and details about a specific Actor. +- `discover-actors`: Searches for relevant Actors using keywords and returns their details. + +There are also tools to manage the available tools list. However, dynamically adding and removing tools requires the MCP client to have the capability to update the tools list (handle `ToolListChangedNotificationSchema`), which is typically not supported. + +You can try this functionality using the [Apify Tester MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) Actor. +To enable it, set the `enableActorAutoLoading` parameter. + +- `add-actor-as-tool`: Adds an Actor by name to the available tools list without executing it, requiring user consent to run later. +- `remove-actor-from-tool`: Removes an Actor by name from the available tools list when it's no longer needed. + +## Prompt & Resources + +The server does not provide any resources and prompts. +We plan to add [Apify's dataset](https://docs.apify.com/platform/storage/dataset) and [key-value store](https://docs.apify.com/platform/storage/key-value-store) as resources in the future. + +# ⚙️ Usage + +The Apify MCP Server can be used in two ways: **as an Apify Actor** running on the Apify platform +or as a **local server** running on your machine. + +## 🇦 MCP Server Actor + +### Standby web server + +The Actor runs in [**Standby mode**](https://docs.apify.com/platform/actors/running/standby) with an HTTP web server that receives and processes requests. + +To start the server with default Actors, send an HTTP GET request with your [Apify API token](https://console.apify.com/settings/integrations) to the following URL: +``` +https://actors-mcp-server.apify.actor?token= +``` +It is also possible to start the MCP server with a different set of Actors. +To do this, create a [task](https://docs.apify.com/platform/actors/running/tasks) and specify the list of Actors you want to use. + +Then, run the task in Standby mode with the selected Actors: +```shell +https://USERNAME--actors-mcp-server-task.apify.actor?token= +``` + +You can find a list of all available Actors in the [Apify Store](https://apify.com/store). + +#### 💬 Interact with the MCP Server over SSE + +Once the server is running, you can interact with Server-Sent Events (SSE) to send messages to the server and receive responses. +The easiest way is to use [Tester MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) on Apify. + +[Claude Desktop](https://claude.ai/download) currently lacks SSE support, but you can use it with Stdio transport; see [MCP Server at a local host](#-mcp-server-at-a-local-host) for more details. +Note: The free version of Claude Desktop may experience intermittent connection issues with the server. + +In the client settings, you need to provide server configuration: +```json +{ + "mcpServers": { + "apify": { + "type": "sse", + "url": "https://actors-mcp-server.apify.actor/sse", + "env": { + "APIFY_TOKEN": "your-apify-token" + } + } + } +} +``` +Alternatively, you can use [clientSse.ts](https://github.com/apify/actor-mcp-server/tree/main/src/examples/clientSse.ts) script or test the server using `curl` commands. + +1. Initiate Server-Sent-Events (SSE) by sending a GET request to the following URL: + ``` + curl https://actors-mcp-server.apify.actor/sse?token= + ``` + The server will respond with a `sessionId`, which you can use to send messages to the server: + ```shell + event: endpoint + data: /message?sessionId=a1b + ``` + +2. Send a message to the server by making a POST request with the `sessionId`: + ```shell + curl -X POST "https://actors-mcp-server.apify.actor/message?token=&session_id=a1b" -H "Content-Type: application/json" -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "tools/call", + "params": { + "arguments": { "searchStringsArray": ["restaurants in San Francisco"], "maxCrawledPlacesPerSearch": 3 }, + "name": "lukaskrivka/google-maps-with-contact-details" + } + }' + ``` + The MCP server will start the Actor `lukaskrivka/google-maps-with-contact-details` with the provided arguments as input parameters. + For this POST request, the server will respond with: + + ```text + Accepted + ``` + +3. Receive the response. The server will invoke the specified Actor as a tool using the provided query parameters and stream the response back to the client via SSE. + The response will be returned as JSON text. + + ```text + event: message + data: {"result":{"content":[{"type":"text","text":"{\"searchString\":\"restaurants in San Francisco\",\"rank\":1,\"title\":\"Gary Danko\",\"description\":\"Renowned chef Gary Danko's fixed-price menus of American cuisine ... \",\"price\":\"$100+\"...}}]}} + ``` + +## ⾕ MCP Server at a local host + +You can run the Apify MCP Server on your local machine by configuring it with Claude Desktop or any other [MCP client](https://modelcontextprotocol.io/clients). +You can also use [Smithery](https://smithery.ai/server/@apify/actors-mcp-server) to install the server automatically. + +### Prerequisites + +- MacOS or Windows +- The latest version of Claude Desktop must be installed (or another MCP client) +- [Node.js](https://nodejs.org/en) (v18 or higher) +- [Apify API Token](https://docs.apify.com/platform/integrations/api#api-token) (`APIFY_TOKEN`) + +Make sure you have the `node` and `npx` installed properly: +```bash +node -v +npx -v +``` +If not, follow this guide to install Node.js: [Downloading and installing Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). + +#### Claude Desktop + +To configure Claude Desktop to work with the MCP server, follow these steps. For a detailed guide, refer to the [Claude Desktop Users Guide](https://modelcontextprotocol.io/quickstart/user). + +1. Download Claude for desktop + - Available for Windows and macOS. + - For Linux users, you can build a Debian package using this [unofficial build script](https://github.com/aaddrick/claude-desktop-debian). +2. Open the Claude Desktop app and enable **Developer Mode** from the top-left menu bar. +3. Once enabled, open **Settings** (also from the top-left menu bar) and navigate to the **Developer Option**, where you'll find the **Edit Config** button. +4. Open the configuration file and edit the following file: + + - On macOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json` + - On Windows: `%APPDATA%/Claude/claude_desktop_config.json` + - On Linux: `~/.config/Claude/claude_desktop_config.json` + + ```json + { + "mcpServers": { + "actors-mcp-server": { + "command": "npx", + "args": ["-y", "@apify/actors-mcp-server"], + "env": { + "APIFY_TOKEN": "your-apify-token" + } + } + } + } + ``` + Alternatively, you can use the `actors` argument to select one or more Apify Actors: + ```json + { + "mcpServers": { + "actors-mcp-server": { + "command": "npx", + "args": [ + "-y", "@apify/actors-mcp-server", + "--actors", "lukaskrivka/google-maps-with-contact-details,apify/instagram-scraper" + ], + "env": { + "APIFY_TOKEN": "your-apify-token" + } + } + } + } + ``` +5. Restart Claude Desktop + + - Fully quit Claude Desktop (ensure it's not just minimized or closed). + - Restart Claude Desktop. + - Look for the 🔌 icon to confirm that the Actors MCP server is connected. + +6. Open the Claude Desktop chat and ask "What Apify Actors can I use?" + + ![Claude-desktop-with-Actors-MCP-server](https://raw.githubusercontent.com/apify/actors-mcp-server/refs/heads/master/docs/claude-desktop.png) + +7. Examples + + You can ask Claude to perform tasks, such as: + ```text + Find and analyze recent research papers about LLMs. + Find the top 10 best Italian restaurants in San Francisco. + Find and analyze the Instagram profile of The Rock. + ``` + +#### VS Code + +For one-click installation, click one of the install buttons below: + +[![Install with NPX in VS Code](https://img.shields.io/badge/VS_Code-NPM-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=actors-mcp-server&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40apify%2Factors-mcp-server%22%5D%2C%22env%22%3A%7B%22APIFY_TOKEN%22%3A%22%24%7Binput%3Aapify_token%7D%22%7D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22apify_token%22%2C%22description%22%3A%22Apify+API+Token%22%2C%22password%22%3Atrue%7D%5D) [![Install with NPX in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-NPM-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=actors-mcp-server&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40apify%2Factors-mcp-server%22%5D%2C%22env%22%3A%7B%22APIFY_TOKEN%22%3A%22%24%7Binput%3Aapify_token%7D%22%7D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22apify_token%22%2C%22description%22%3A%22Apify+API+Token%22%2C%22password%22%3Atrue%7D%5D&quality=insiders) + +##### Manual installation + +You can manually install the Apify MCP Server in VS Code. First, click one of the install buttons at the top of this section for a one-click installation. + +Alternatively, add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing `Ctrl + Shift + P` and typing `Preferences: Open User Settings (JSON)`. + +```json +{ + "mcp": { + "inputs": [ + { + "type": "promptString", + "id": "apify_token", + "description": "Apify API Token", + "password": true + } + ], + "servers": { + "actors-mcp-server": { + "command": "npx", + "args": ["-y", "@apify/actors-mcp-server"], + "env": { + "APIFY_TOKEN": "${input:apify_token}" + } + } + } + } +} +``` + +Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace - just omit the top-level `mcp {}` key. This will allow you to share the configuration with others. + +If you want to specify which Actors to load, you can add the `--actors` argument: + +```json +{ + "servers": { + "actors-mcp-server": { + "command": "npx", + "args": [ + "-y", "@apify/actors-mcp-server", + "--actors", "lukaskrivka/google-maps-with-contact-details,apify/instagram-scraper" + ], + "env": { + "APIFY_TOKEN": "${input:apify_token}" + } + } + } +} +``` + +#### VS Code + +For one-click installation, click one of the install buttons below: + +[![Install with NPX in VS Code](https://img.shields.io/badge/VS_Code-NPM-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=actors-mcp-server&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40apify%2Factors-mcp-server%22%5D%2C%22env%22%3A%7B%22APIFY_TOKEN%22%3A%22%24%7Binput%3Aapify_token%7D%22%7D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22apify_token%22%2C%22description%22%3A%22Apify+API+Token%22%2C%22password%22%3Atrue%7D%5D) [![Install with NPX in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-NPM-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=actors-mcp-server&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40apify%2Factors-mcp-server%22%5D%2C%22env%22%3A%7B%22APIFY_TOKEN%22%3A%22%24%7Binput%3Aapify_token%7D%22%7D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22apify_token%22%2C%22description%22%3A%22Apify+API+Token%22%2C%22password%22%3Atrue%7D%5D&quality=insiders) + +##### Manual installation + +You can manually install the Apify MCP Server in VS Code. First, click one of the install buttons at the top of this section for a one-click installation. + +Alternatively, add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing `Ctrl + Shift + P` and typing `Preferences: Open User Settings (JSON)`. + +```json +{ + "mcp": { + "inputs": [ + { + "type": "promptString", + "id": "apify_token", + "description": "Apify API Token", + "password": true + } + ], + "servers": { + "actors-mcp-server": { + "command": "npx", + "args": ["-y", "@apify/actors-mcp-server"], + "env": { + "APIFY_TOKEN": "${input:apify_token}" + } + } + } + } +} +``` + +Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace - just omit the top-level `mcp {}` key. This will allow you to share the configuration with others. + +If you want to specify which Actors to load, you can add the `--actors` argument: + +```json +{ + "servers": { + "actors-mcp-server": { + "command": "npx", + "args": [ + "-y", "@apify/actors-mcp-server", + "--actors", "lukaskrivka/google-maps-with-contact-details,apify/instagram-scraper" + ], + "env": { + "APIFY_TOKEN": "${input:apify_token}" + } + } + } +} +``` + +#### Debugging NPM package @apify/actors-mcp-server with @modelcontextprotocol/inspector + +To debug the server, use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) tool: + +```shell +export APIFY_TOKEN=your-apify-token +npx @modelcontextprotocol/inspector npx -y @apify/actors-mcp-server +``` + +### Installing via Smithery + +To install Apify Actors MCP Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@apify/actors-mcp-server): + +```bash +npx -y @smithery/cli install @apify/actors-mcp-server --client claude +``` + +#### Stdio clients + +Create an environment file `.env` with the following content: +```text +APIFY_TOKEN=your-apify-token +``` +In the `examples` directory, you can find an example client to interact with the server via +standard input/output (stdio): + +- [`clientStdio.ts`](https://github.com/apify/actor-mcp-server/tree/main/src/examples/clientStdio.ts) + This client script starts the MCP server with two specified Actors. + It then calls the `apify/rag-web-browser` tool with a query and prints the result. + It demonstrates how to connect to the MCP server, list available tools, and call a specific tool using stdio transport. + ```bash + node dist/examples/clientStdio.js + ``` + +# 👷🏼 Development + +## Prerequisites + +- [Node.js](https://nodejs.org/en) (v18 or higher) +- Python 3.9 or higher + +Create an environment file `.env` with the following content: +```text +APIFY_TOKEN=your-apify-token +``` + +Build the actor-mcp-server package: + +```bash +npm run build +``` + +## Local client (SSE) + +To test the server with the SSE transport, you can use the script `examples/clientSse.ts`: +Currently, the Node.js client does not support establishing a connection to a remote server with custom headers. +You need to change the URL to your local server URL in the script. + +```bash +node dist/examples/clientSse.js +``` + +## Debugging + +Since MCP servers operate over standard input/output (stdio), debugging can be challenging. +For the best debugging experience, use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). + +You can launch the MCP Inspector via [`npm`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) with this command: + +```bash +export APIFY_TOKEN=your-apify-token +npx @modelcontextprotocol/inspector node ./dist/stdio.js +``` + +Upon launching, the Inspector will display a URL that you can access in your browser to begin debugging. + +## ⓘ Limitations and feedback + +The Actor input schema is processed to be compatible with most MCP clients while adhering to [JSON Schema](https://json-schema.org/) standards. The processing includes: +- **Descriptions** are truncated to 500 characters (as defined in `MAX_DESCRIPTION_LENGTH`). +- **Enum fields** are truncated to a maximum combined length of 200 characters for all elements (as defined in `ACTOR_ENUM_MAX_LENGTH`). +- **Required fields** are explicitly marked with a "REQUIRED" prefix in their descriptions for compatibility with frameworks that may not handle JSON schema properly. +- **Nested properties** are built for special cases like proxy configuration and request list sources to ensure correct input structure. +- **Array item types** are inferred when not explicitly defined in the schema, using a priority order: explicit type in items > prefill type > default value type > editor type. +- **Enum values and examples** are added to property descriptions to ensure visibility even if the client doesn't fully support JSON schema. + +Memory for each Actor is limited to 4GB. +Free users have an 8GB limit, 128MB needs to be allocated for running `Actors-MCP-Server`. + +If you need other features or have any feedback, [submit an issue](https://console.apify.com/actors/1lSvMAaRcadrM1Vgv/issues) in Apify Console to let us know. + +# 🚀 Roadmap (March 2025) + +- Add Apify's dataset and key-value store as resources. +- Add tools such as Actor logs and Actor runs for debugging. + +# 🐛 Troubleshooting + +- Make sure you have the `node` installed by running `node -v` +- Make sure you have the `APIFY_TOKEN` environment variable set +- Always use the latest version of the MCP server by setting `@apify/actors-mcp-server@latest` + +# 📚 Learn more + +- [Model Context Protocol](https://modelcontextprotocol.org/) +- [What are AI Agents?](https://blog.apify.com/what-are-ai-agents/) +- [What is MCP and why does it matter?](https://blog.apify.com/what-is-model-context-protocol/) +- [Tester MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) +- [AI agent workflow: building an agent to query Apify datasets](https://blog.apify.com/ai-agent-workflow/) +- [MCP Client development guide](https://github.com/cyanheads/model-context-protocol-resources/blob/main/guides/mcp-client-development-guide.md) +- [How to build and monetize an AI agent on Apify](https://blog.apify.com/how-to-build-an-ai-agent/) diff --git a/.actor/actor.json b/.actor/actor.json index 6ec16cc4..a518a22e 100644 --- a/.actor/actor.json +++ b/.actor/actor.json @@ -5,6 +5,7 @@ "description": "Implementation of a Model Context Protocol (MCP) Server for Apify Actors that enables AI applications (and AI agents) to interact with Apify Actors", "version": "0.1", "input": "./input_schema.json", + "readme": "./ACTOR.md", "dockerfile": "./Dockerfile", "webServerMcpPath": "/sse" } diff --git a/.github/scripts/before-beta-release.cjs b/.github/scripts/before-beta-release.cjs index 26ae4e1f..5d38045f 100644 --- a/.github/scripts/before-beta-release.cjs +++ b/.github/scripts/before-beta-release.cjs @@ -1,6 +1,6 @@ -const { execSync } = require('child_process'); -const fs = require('fs'); -const path = require('path'); +const { execSync } = require('node:child_process'); +const fs = require('node:fs'); +const path = require('node:path'); const PKG_JSON_PATH = path.join(__dirname, '..', '..', 'package.json'); diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 91f8c74e..6d0364bd 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -36,3 +36,6 @@ jobs: - name: Test run: npm run test + + - name: Type checks + run: npm run type-check diff --git a/.gitignore b/.gitignore index 1e23c8f4..75950be2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ storage/key_value_stores/default/* # Added by Apify CLI .venv .env +.aider* diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..d5b283a3 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22.13.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ffccf5f..84650745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -179,4 +179,4 @@ All notable changes to this project will be documented in this file. ### 🐛 Bug Fixes - Update express routes to correctly handle GET and HEAD requests, fix CI ([#5](https://github.com/apify/actors-mcp-server/pull/5)) ([ec6e9b0](https://github.com/apify/actors-mcp-server/commit/ec6e9b0a4657f673b3650a5906fe00e66411d7f1)) by [@jirispilka](https://github.com/jirispilka) -- Correct publishing of npm module ([#6](https://github.com/apify/actors-mcp-server/pull/6)) ([4c953e9](https://github.com/apify/actors-mcp-server/commit/4c953e9fe0c735f1690c8356884dd78d8608979f)) by [@jirispilka](https://github.com/jirispilka) \ No newline at end of file +- Correct publishing of npm module ([#6](https://github.com/apify/actors-mcp-server/pull/6)) ([4c953e9](https://github.com/apify/actors-mcp-server/commit/4c953e9fe0c735f1690c8356884dd78d8608979f)) by [@jirispilka](https://github.com/jirispilka) diff --git a/README.md b/README.md index 7560f4de..6d2c8417 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ The server can be used in two ways: - **🇦 [MCP Server Actor](https://apify.com/apify/actors-mcp-server)** – HTTP server accessible via Server-Sent Events (SSE), see [guide](#-mcp-server-actor) - **⾕ MCP Server Stdio** – Local server available via standard input/output (stdio), see [guide](#-mcp-server-at-a-local-host) - You can also interact with the MCP server using a chat-like UI with 💬 [Tester MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) # 🎯 What does Apify MCP server do? @@ -337,6 +336,63 @@ If you want to specify which Actors to load, you can add the `--actors` argument } ``` +#### VS Code + +For one-click installation, click one of the install buttons below: + +[![Install with NPX in VS Code](https://img.shields.io/badge/VS_Code-NPM-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=actors-mcp-server&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40apify%2Factors-mcp-server%22%5D%2C%22env%22%3A%7B%22APIFY_TOKEN%22%3A%22%24%7Binput%3Aapify_token%7D%22%7D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22apify_token%22%2C%22description%22%3A%22Apify+API+Token%22%2C%22password%22%3Atrue%7D%5D) [![Install with NPX in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-NPM-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=actors-mcp-server&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40apify%2Factors-mcp-server%22%5D%2C%22env%22%3A%7B%22APIFY_TOKEN%22%3A%22%24%7Binput%3Aapify_token%7D%22%7D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22apify_token%22%2C%22description%22%3A%22Apify+API+Token%22%2C%22password%22%3Atrue%7D%5D&quality=insiders) + +##### Manual installation + +You can manually install the Apify MCP Server in VS Code. First, click one of the install buttons at the top of this section for a one-click installation. + +Alternatively, add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing `Ctrl + Shift + P` and typing `Preferences: Open User Settings (JSON)`. + +```json +{ + "mcp": { + "inputs": [ + { + "type": "promptString", + "id": "apify_token", + "description": "Apify API Token", + "password": true + } + ], + "servers": { + "actors-mcp-server": { + "command": "npx", + "args": ["-y", "@apify/actors-mcp-server"], + "env": { + "APIFY_TOKEN": "${input:apify_token}" + } + } + } + } +} +``` + +Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace - just omit the top-level `mcp {}` key. This will allow you to share the configuration with others. + +If you want to specify which Actors to load, you can add the `--actors` argument: + +```json +{ + "servers": { + "actors-mcp-server": { + "command": "npx", + "args": [ + "-y", "@apify/actors-mcp-server", + "--actors", "lukaskrivka/google-maps-with-contact-details,apify/instagram-scraper" + ], + "env": { + "APIFY_TOKEN": "${input:apify_token}" + } + } + } +} +``` + #### Debugging NPM package @apify/actors-mcp-server with @modelcontextprotocol/inspector To debug the server, use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) tool: @@ -408,7 +464,7 @@ You can launch the MCP Inspector via [`npm`](https://docs.npmjs.com/downloading- ```bash export APIFY_TOKEN=your-apify-token -npx @modelcontextprotocol/inspector node ./dist/index.js +npx @modelcontextprotocol/inspector node ./dist/stdio.js ``` Upon launching, the Inspector will display a URL that you can access in your browser to begin debugging. diff --git a/eslint.config.mjs b/eslint.config.mjs index ffe1b904..fb9cd123 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,9 +1,9 @@ -import apify from '@apify/eslint-config'; +import apifyTypeScriptConfig from '@apify/eslint-config/ts.js'; // eslint-disable-next-line import/no-default-export export default [ - { ignores: ['**/dist', '**/.venv'] }, // Ignores need to happen first - ...apify, + { ignores: ['**/dist'] }, // Ignores need to happen first + ...apifyTypeScriptConfig, { languageOptions: { sourceType: 'module', diff --git a/package-lock.json b/package-lock.json index d4836583..85848c6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,32 +9,33 @@ "version": "0.1.23", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.3.1", + "@apify/log": "^2.5.16", + "@modelcontextprotocol/sdk": "github:jirispilka/mcp-typescript-sdk#fix/add-src-dir", "ajv": "^8.17.1", - "apify": "^3.2.6", - "apify-client": "^2.11.2", + "apify": "^3.4.0", + "apify-client": "^2.12.1", "express": "^4.21.2", - "yargs-parser": "^21.1.1", + "minimist": "^1.2.8", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.1" }, "bin": { - "actors-mcp-server": "dist/index.js" + "actors-mcp-server": "dist/stdio.js" }, "devDependencies": { "@anthropic-ai/sdk": "^0.33.1", "@anthropic-ai/tokenizer": "^0.0.4", - "@apify/eslint-config": "^0.5.0-beta.2", + "@apify/eslint-config": "^1.0.0", "@apify/tsconfig": "^0.1.0", "@types/express": "^4.0.0", "@types/minimist": "^1.2.5", "@types/yargs-parser": "^21.0.3", "dotenv": "^16.4.7", - "eslint": "^9.17.0", + "eslint": "^9.19.0", "eventsource": "^3.0.2", "tsx": "^4.6.2", "typescript": "^5.3.3", - "typescript-eslint": "^8.18.2", + "typescript-eslint": "^8.23.0", "vitest": "^3.0.8" }, "engines": { @@ -57,30 +58,6 @@ "node-fetch": "^2.6.7" } }, - "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { - "version": "18.19.70", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.70.tgz", - "integrity": "sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@anthropic-ai/sdk/node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@anthropic-ai/sdk/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, - "license": "MIT" - }, "node_modules/@anthropic-ai/tokenizer": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@anthropic-ai/tokenizer/-/tokenizer-0.0.4.tgz", @@ -92,75 +69,64 @@ "tiktoken": "^1.0.10" } }, - "node_modules/@anthropic-ai/tokenizer/node_modules/@types/node": { - "version": "18.19.70", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.70.tgz", - "integrity": "sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@anthropic-ai/tokenizer/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, - "license": "MIT" - }, "node_modules/@apify/consts": { - "version": "2.35.0", - "resolved": "https://registry.npmjs.org/@apify/consts/-/consts-2.35.0.tgz", - "integrity": "sha512-ICUoIzyxSWuQZXtMwMxrnfogPTagQS2fDY1jgZZCikv4WF0c4a3/HKpIprHZ3lI90+jjF0r8TtEVEcWIaRgP4Q==", + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/@apify/consts/-/consts-2.40.0.tgz", + "integrity": "sha512-2coaQ97ddsQ4+QRybqGbPE4irqfmkSaUPlbUPQvIcmT+PLdFT1t1iSU61Yy2T1UW5wN3K6UDAqFWNIqxxb0apg==", "license": "Apache-2.0" }, "node_modules/@apify/datastructures": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apify/datastructures/-/datastructures-2.0.2.tgz", - "integrity": "sha512-IN9A0s2SCHoZZE1tf4xKgk4fxHM5/0I/UrXhWbn/rSv7E5sA2o0NyHdwcMY2Go9f5qd+E7VAbX6WnESTE6GLeA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@apify/datastructures/-/datastructures-2.0.3.tgz", + "integrity": "sha512-E6yQyc/XZDqJopbaGmhzZXMJqwGf96ELtDANZa0t68jcOAJZS+pF7YUfQOLszXq6JQAdnRvTH2caotL6urX7HA==", "license": "Apache-2.0" }, "node_modules/@apify/eslint-config": { - "version": "0.5.0-beta.2", - "resolved": "https://registry.npmjs.org/@apify/eslint-config/-/eslint-config-0.5.0-beta.2.tgz", - "integrity": "sha512-I6Eb8w62HTMRVVjp86NtV1nQiU24qycqOrEA0NkYuAjcdZiNTmxVBoz1hIyQcerp9kdQ9r3c3p9I6lb+uoRuyQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@apify/eslint-config/-/eslint-config-1.0.0.tgz", + "integrity": "sha512-8dAMgX5qf7B5W5NhzymtweD1Llh7f4gytgg3kYtyA1bVBdh3BT3cTUhEUDeeZSyeyQL2ZkSMPrfLP/3sd5dcUA==", "dev": true, "license": "ISC", "dependencies": { - "@eslint/compat": "^1.2.2", + "@eslint/compat": "^1.2.6", + "@jirimoravcik/eslint-plugin-import": "2.32.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.31.0", - "globals": "^15.11.0" + "eslint-plugin-simple-import-sort": "^12.1.1", + "globals": "^15.14.0" }, "peerDependencies": { - "eslint": "^9.0.0", - "typescript-eslint": "^8.0.0" + "eslint": "^9.19.0", + "eslint-plugin-jest": "^28.11.0", + "typescript-eslint": "^8.23.0" }, "peerDependenciesMeta": { + "eslint-plugin-jest": { + "optional": true + }, "typescript-eslint": { "optional": true } } }, "node_modules/@apify/input_secrets": { - "version": "1.1.60", - "resolved": "https://registry.npmjs.org/@apify/input_secrets/-/input_secrets-1.1.60.tgz", - "integrity": "sha512-ZSL6aCjCs/zjq5Y6187G6FlstGKmUD3vmx4Ew+C20lnxRyAFUd3wuk+lrDvfuRl9KB8GHvXod+UIGna6+/UMZw==", + "version": "1.1.71", + "resolved": "https://registry.npmjs.org/@apify/input_secrets/-/input_secrets-1.1.71.tgz", + "integrity": "sha512-vLdbRNZkVAOpgqHtho+AGIgWLgaeB4fV2B43oPm9pDbdX+Iv5X+04OM8Gh/X/Gcxs4ssdVXgb/hRy0uDxVa/Uw==", "license": "Apache-2.0", "dependencies": { - "@apify/log": "^2.5.11", - "@apify/utilities": "^2.11.1", + "@apify/log": "^2.5.17", + "@apify/utilities": "^2.15.4", "ow": "^0.28.2" } }, "node_modules/@apify/log": { - "version": "2.5.11", - "resolved": "https://registry.npmjs.org/@apify/log/-/log-2.5.11.tgz", - "integrity": "sha512-QDAFqOsZkpeV3UR9eYCGskI8rHSDnhF+hnbUea3MvfIhH5PfvbWIpdUrb7s04XnfnXbWpRSN+7TYLWBbHf+X5Q==", + "version": "2.5.17", + "resolved": "https://registry.npmjs.org/@apify/log/-/log-2.5.17.tgz", + "integrity": "sha512-1L/iiHRxyc8e0EuFfZ1raZLWC4mQYrTPy9JzF1hwwhsRSlyHNFQrfNzF0vbF3/8XpLwEBSasAA3fclQhDbUn/Q==", "license": "Apache-2.0", "dependencies": { - "@apify/consts": "^2.35.0", + "@apify/consts": "^2.40.0", "ansi-colors": "^4.1.1" } }, @@ -180,41 +146,41 @@ } }, "node_modules/@apify/pseudo_url": { - "version": "2.0.52", - "resolved": "https://registry.npmjs.org/@apify/pseudo_url/-/pseudo_url-2.0.52.tgz", - "integrity": "sha512-7YhvBhcKLBlM9Pz4HsvpBhO7dyFmWf1gY4xldgEgPyIwlkycP6rsqg73U2fHxb5oUaxFPk99jBIaEwmIhonSGw==", + "version": "2.0.58", + "resolved": "https://registry.npmjs.org/@apify/pseudo_url/-/pseudo_url-2.0.58.tgz", + "integrity": "sha512-a0F94mEhwZJe6UUO3JGVbvufNqSQkP3uc0nLAAJA7Bydwe5PMRrWGLQ8+/EW8pEnrYCFVTuI9+uXtJideQpinA==", "license": "Apache-2.0", "dependencies": { - "@apify/log": "^2.5.11" + "@apify/log": "^2.5.17" } }, "node_modules/@apify/timeout": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@apify/timeout/-/timeout-0.3.1.tgz", - "integrity": "sha512-sLIuOqfySki/7AXiQ1yZoCI07vX6aYFLgP6YaJ8e8YLn8CFsRERma/Crxcz0zyCaxhc7C7EPgcs1O+p/djZchw==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@apify/timeout/-/timeout-0.3.2.tgz", + "integrity": "sha512-JnOLIOpqfm366q7opKrA6HrL0iYRpYYDn8Mi77sMR2GZ1fPbwMWCVzN23LJWfJV7izetZbCMrqRUXsR1etZ7dA==", "license": "Apache-2.0" }, "node_modules/@apify/tsconfig": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@apify/tsconfig/-/tsconfig-0.1.0.tgz", - "integrity": "sha512-ba9Y6AMocRucO3AVTb6GM2V+oy1wByNlCDzamK+IC+aqU3pCgJwSN87uNu6iEgu+uetsqYvVbXJYakwiQO1LGA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@apify/tsconfig/-/tsconfig-0.1.1.tgz", + "integrity": "sha512-cS7mwN2UW1UXcluGXRDHH0Vr2VsSLkw2DwLTwoSBkcJSe8fvCr3MPryTSq0uod4MashpMURxJ7CsLKxs82VmOQ==", "dev": true, "license": "Apache-2.0" }, "node_modules/@apify/utilities": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@apify/utilities/-/utilities-2.11.1.tgz", - "integrity": "sha512-g0oll9k7CG+ivwQ9mZiMuEZQHUXbrO+zdPtIY5xliUrp4UmJ0mmnbf6JOk3GXOeAcZaM4Acfm7g9H18Bxih1mA==", + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/@apify/utilities/-/utilities-2.15.4.tgz", + "integrity": "sha512-uM1kLJAE3bnDApGPqdD0xWeo/2HCE9KyAxeBdtRNaHVOu8DvRf8ioOlif75AZbMCXCo3g0zNmkznjtR6hrglJw==", "license": "Apache-2.0", "dependencies": { - "@apify/consts": "^2.35.0", - "@apify/log": "^2.5.11" + "@apify/consts": "^2.40.0", + "@apify/log": "^2.5.17" } }, "node_modules/@crawlee/core": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@crawlee/core/-/core-3.12.1.tgz", - "integrity": "sha512-hom1ALM1Gn+ZpdFxIcQwmNjHV7mZhcOsPGIqhZuEWSETPV3lcMX67ZPs9UU3nIjsPgKuDC3FjIv6TXNu8Ga55A==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/@crawlee/core/-/core-3.13.2.tgz", + "integrity": "sha512-k37uWReG4zztMoloFpmLlNP7Sc+LfpCr26xGIimu5pHTqjtegpN6VFI1k8N3pPSdqYWXMFCXnzsQWdTxZ/7Iyw==", "license": "Apache-2.0", "dependencies": { "@apify/consts": "^2.20.0", @@ -223,9 +189,9 @@ "@apify/pseudo_url": "^2.0.30", "@apify/timeout": "^0.3.0", "@apify/utilities": "^2.7.10", - "@crawlee/memory-storage": "3.12.1", - "@crawlee/types": "3.12.1", - "@crawlee/utils": "3.12.1", + "@crawlee/memory-storage": "3.13.2", + "@crawlee/types": "3.13.2", + "@crawlee/utils": "3.13.2", "@sapphire/async-queue": "^1.5.1", "@vladfrangu/async_event_emitter": "^2.2.2", "csv-stringify": "^6.2.0", @@ -244,14 +210,38 @@ "node": ">=16.0.0" } }, + "node_modules/@crawlee/core/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==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@crawlee/core/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@crawlee/memory-storage": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@crawlee/memory-storage/-/memory-storage-3.12.1.tgz", - "integrity": "sha512-N3WqfNIgo8m5ycJvUM5BvAZoqgglwEq11HsIlAUX4AGRKfYiFLziGpkBdhm2JAaD3/VWyZeEKyWgpkRiKZXo2w==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/@crawlee/memory-storage/-/memory-storage-3.13.2.tgz", + "integrity": "sha512-vJDffE9pUOQ56VCcCdaCG9viDkxbwiuog1j/2lwi0uIGLeoE5SR0OrGJF9Gr2UfD2t3jY+m+T0ZY2p+NaxwuhQ==", "license": "Apache-2.0", "dependencies": { "@apify/log": "^2.4.0", - "@crawlee/types": "3.12.1", + "@crawlee/types": "3.13.2", "@sapphire/async-queue": "^1.5.0", "@sapphire/shapeshift": "^3.0.0", "content-type": "^1.0.4", @@ -266,9 +256,9 @@ } }, "node_modules/@crawlee/types": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@crawlee/types/-/types-3.12.1.tgz", - "integrity": "sha512-KiYqRxYTB89Osy7sBbKhOSUyUusO85aGHvLLzxWAjQPrIhrY09t2kuVZhmTnjXTbgucQdMeWFrQjQuNeq8yPtA==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/@crawlee/types/-/types-3.13.2.tgz", + "integrity": "sha512-7LASqr6Uwj049vMy5XCb0j9BBIKP3RdDKV2B74x5JheSss/fsj8+2pa+RJQL4L7tvIzKK36ndmYzQ0v83H0vbQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.4.0" @@ -278,17 +268,17 @@ } }, "node_modules/@crawlee/utils": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@crawlee/utils/-/utils-3.12.1.tgz", - "integrity": "sha512-GknM4VD77coaAXkb2MPRkqYGVWHGMPUDuyBFmMZLGPnenHX7VoywZK+4Xw5o6FMLk0krPF/oAPAyD52fHv2B2Q==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/@crawlee/utils/-/utils-3.13.2.tgz", + "integrity": "sha512-Nn/lXdaNoD47+CyYx8tv86KuFj6gyrEzZT9bvZoIs1sKIx4ZZNEFa/A4yQqQkaJX+UfFWBp2NK48LDSr+Og69w==", "license": "Apache-2.0", "dependencies": { "@apify/log": "^2.4.0", "@apify/ps-tree": "^1.2.0", - "@crawlee/types": "3.12.1", + "@crawlee/types": "3.13.2", "@types/sax": "^1.2.7", "cheerio": "1.0.0-rc.12", - "file-type": "^19.0.0", + "file-type": "^20.0.0", "got-scraping": "^4.0.3", "ow": "^0.28.1", "robots-parser": "^3.0.1", @@ -300,50 +290,10 @@ "node": ">=16.0.0" } }, - "node_modules/@crawlee/utils/node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "license": "MIT", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/@crawlee/utils/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", - "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", "cpu": [ "ppc64" ], @@ -358,9 +308,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", - "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", "cpu": [ "arm" ], @@ -375,9 +325,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", - "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", "cpu": [ "arm64" ], @@ -392,9 +342,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", - "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", "cpu": [ "x64" ], @@ -409,9 +359,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", - "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", "cpu": [ "arm64" ], @@ -426,9 +376,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", - "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", "cpu": [ "x64" ], @@ -443,9 +393,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", - "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", "cpu": [ "arm64" ], @@ -460,9 +410,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", - "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", "cpu": [ "x64" ], @@ -477,9 +427,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", - "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", "cpu": [ "arm" ], @@ -494,9 +444,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", - "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", "cpu": [ "arm64" ], @@ -511,9 +461,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", - "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", "cpu": [ "ia32" ], @@ -528,9 +478,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", - "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", "cpu": [ "loong64" ], @@ -545,9 +495,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", - "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", "cpu": [ "mips64el" ], @@ -562,9 +512,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", - "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", "cpu": [ "ppc64" ], @@ -579,9 +529,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", - "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", "cpu": [ "riscv64" ], @@ -596,9 +546,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", - "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", "cpu": [ "s390x" ], @@ -613,9 +563,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", - "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", "cpu": [ "x64" ], @@ -630,13 +580,14 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", - "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -646,9 +597,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", - "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", "cpu": [ "x64" ], @@ -663,9 +614,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", - "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", "cpu": [ "arm64" ], @@ -680,9 +631,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", - "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", "cpu": [ "x64" ], @@ -697,9 +648,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", - "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", "cpu": [ "x64" ], @@ -714,9 +665,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", - "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", "cpu": [ "arm64" ], @@ -731,9 +682,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", - "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", "cpu": [ "ia32" ], @@ -748,9 +699,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", - "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", "cpu": [ "x64" ], @@ -765,9 +716,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "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": { @@ -807,9 +758,9 @@ } }, "node_modules/@eslint/compat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.4.tgz", - "integrity": "sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.8.tgz", + "integrity": "sha512-LqCYHdWL/QqKIJuZ/ucMAv8d4luKGs4oCPgpt8mWztQAtPrHfXKQ/XAUc8ljCHAfJCn6SvkpTcGt5Tsh8saowA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -825,13 +776,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "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.5", + "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -839,34 +790,38 @@ "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==", + "node_modules/@eslint/config-array/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==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "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==", + "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": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "Apache-2.0", "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", - "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -877,9 +832,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { @@ -917,15 +872,22 @@ "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==", + "node_modules/@eslint/eslintrc/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==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/@eslint/eslintrc/node_modules/globals": { @@ -948,23 +910,10 @@ "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.17.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", - "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz", + "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==", "dev": true, "license": "MIT", "engines": { @@ -972,9 +921,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", - "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "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": { @@ -982,18 +931,32 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", - "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "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/@eslint/plugin-kit/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/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1047,9 +1010,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "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": { @@ -1060,19 +1023,59 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@jirimoravcik/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/@jirimoravcik/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-WkGO098hw9/rFizGLQHTDWruVGetXLOXs6pENWfWkIKXHk4qh5vfBuXvEhyO9Y9+ESfHFIJKAp1heo1B/Ozg8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.3.1.tgz", - "integrity": "sha512-Fu3HstNO03/S5nvwh3KjRfP5JOSMl6IbOBxRl6JBDXMFRHPSJ4kiiV7n5yJjY51GtrFw3Y+V/vdsweN5bxULWQ==", + "version": "1.10.0", + "resolved": "git+ssh://git@github.com/jirispilka/mcp-typescript-sdk.git#4ae4b33f263ec0ab157eb5f541c69ba01cbf2822", "license": "MIT", "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" @@ -1081,286 +1084,587 @@ "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, + "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, "engines": { - "node": ">= 8" + "node": ">= 0.6" } }, - "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, + "node_modules/@modelcontextprotocol/sdk/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", + "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": ">= 8" + "node": ">=18" } }, - "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, + "node_modules/@modelcontextprotocol/sdk/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", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "safe-buffer": "5.2.1" }, "engines": { - "node": ">= 8" + "node": ">= 0.6" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", - "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] + "node_modules/@modelcontextprotocol/sdk/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", + "engines": { + "node": ">=6.6.0" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", - "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" + "node_modules/@modelcontextprotocol/sdk/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/@modelcontextprotocol/sdk/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", + "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/@modelcontextprotocol/sdk/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", + "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/@modelcontextprotocol/sdk/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", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "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/@modelcontextprotocol/sdk/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", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@modelcontextprotocol/sdk/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", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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/@rollup/rollup-android-arm-eabi": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", + "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", + "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", - "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", + "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", - "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", + "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", - "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", + "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", - "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", + "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", - "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", + "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", - "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", + "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", - "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", + "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", - "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", + "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", - "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", + "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", - "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", + "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", - "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", + "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", + "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", - "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", + "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", - "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", + "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", - "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", + "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", - "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", + "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", - "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", + "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", - "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", + "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1426,6 +1730,41 @@ "node": ">=14.16" } }, + "node_modules/@tokenizer/inflate": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.2.7.tgz", + "integrity": "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fflate": "^0.8.2", + "token-types": "^6.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/inflate/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/@tokenizer/token": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", @@ -1454,9 +1793,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "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" }, @@ -1528,12 +1867,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "version": "18.19.86", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", + "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~5.26.4" } }, "node_modules/@types/node-fetch": { @@ -1548,9 +1887,9 @@ } }, "node_modules/@types/qs": { - "version": "6.9.17", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", - "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", "dev": true, "license": "MIT" }, @@ -1597,24 +1936,25 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz", - "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.30.1.tgz", + "integrity": "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/type-utils": "8.18.2", - "@typescript-eslint/utils": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/type-utils": "8.30.1", + "@typescript-eslint/utils": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1626,20 +1966,20 @@ "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.2.tgz", - "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.30.1.tgz", + "integrity": "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/typescript-estree": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/typescript-estree": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "debug": "^4.3.4" }, "engines": { @@ -1651,38 +1991,56 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.2.tgz", - "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", + "node_modules/@typescript-eslint/parser/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==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2" + "ms": "^2.1.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=6.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.2.tgz", - "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.30.1.tgz", + "integrity": "sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1" + }, + "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.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.30.1.tgz", + "integrity": "sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.18.2", - "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/typescript-estree": "8.30.1", + "@typescript-eslint/utils": "8.30.1", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1693,13 +2051,31 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/@typescript-eslint/types": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.2.tgz", - "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.30.1.tgz", + "integrity": "sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw==", "dev": true, "license": "MIT", "engines": { @@ -1711,20 +2087,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.2.tgz", - "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.30.1.tgz", + "integrity": "sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "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": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1734,20 +2110,77 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.2.tgz", - "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.30.1.tgz", + "integrity": "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/typescript-estree": "8.18.2" + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/typescript-estree": "8.30.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1758,17 +2191,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.2.tgz", - "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.30.1.tgz", + "integrity": "sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/types": "8.30.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -1780,13 +2213,14 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.8.tgz", - "integrity": "sha512-Xu6TTIavTvSSS6LZaA3EebWFr6tsoXPetOWNMOlc7LO88QVVBwq2oQWBoDiLCN6YTvNYsGSjqOO8CAdjom5DCQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.1.1.tgz", + "integrity": "sha512-q/zjrW9lgynctNbwvFtQkGK9+vvHA5UzVi2V8APrp1C6fG6/MuYYkmlx4FubuqLycCeSdHD5aadWfua/Vr0EUA==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.8", - "@vitest/utils": "3.0.8", + "@vitest/spy": "3.1.1", + "@vitest/utils": "3.1.1", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -1795,12 +2229,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.8.tgz", - "integrity": "sha512-n3LjS7fcW1BCoF+zWZxG7/5XvuYH+lsFg+BDwwAz0arIwHQJFUEsKBQ0BLU49fCxuM/2HSeBPHQD8WjgrxMfow==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.1.1.tgz", + "integrity": "sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.8", + "@vitest/spy": "3.1.1", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -1821,10 +2256,11 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.8.tgz", - "integrity": "sha512-BNqwbEyitFhzYMYHUVbIvepOyeQOSFA/NeJMIP9enMntkkxLgOcgABH6fjyXG85ipTgvero6noreavGIqfJcIg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.1.tgz", + "integrity": "sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA==", "dev": true, + "license": "MIT", "dependencies": { "tinyrainbow": "^2.0.0" }, @@ -1833,12 +2269,13 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.8.tgz", - "integrity": "sha512-c7UUw6gEcOzI8fih+uaAXS5DwjlBaCJUo7KJ4VvJcjL95+DSR1kova2hFuRt3w41KZEFcOEiq098KkyrjXeM5w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.1.1.tgz", + "integrity": "sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.8", + "@vitest/utils": "3.1.1", "pathe": "^2.0.3" }, "funding": { @@ -1846,12 +2283,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.8.tgz", - "integrity": "sha512-x8IlMGSEMugakInj44nUrLSILh/zy1f2/BgH0UeHpNyOocG18M9CWVIFBaXPt8TrqVZWmcPjwfG/ht5tnpba8A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.1.1.tgz", + "integrity": "sha512-bByMwaVWe/+1WDf9exFxWWgAixelSdiwo2p33tpqIlM14vW7PRV5ppayVXtfycqze4Qhtwag5sVhX400MLBOOw==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.8", + "@vitest/pretty-format": "3.1.1", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -1860,10 +2298,11 @@ } }, "node_modules/@vitest/spy": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.8.tgz", - "integrity": "sha512-MR+PzJa+22vFKYb934CejhR4BeRpMSoxkvNoDit68GQxRLSf11aT6CTj3XaqUU9rxgWJFnqicN/wxw6yBRkI1Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.1.1.tgz", + "integrity": "sha512-+EmrUOOXbKzLkTDwlsc/xrwOlPDXyVk3Z6P6K4oiCndxz7YLpp/0R0UsWVOKT0IXWjjBJuSMk6D27qipaupcvQ==", "dev": true, + "license": "MIT", "dependencies": { "tinyspy": "^3.0.2" }, @@ -1872,12 +2311,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.8.tgz", - "integrity": "sha512-nkBC3aEhfX2PdtQI/QwAWp8qZWwzASsU4Npbcd5RdMPBSSLCpkZp52P3xku3s3uA0HIEhGvEcF8rNkBsz9dQ4Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.1.1.tgz", + "integrity": "sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.8", + "@vitest/pretty-format": "3.1.1", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" }, @@ -1922,9 +2362,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "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": { @@ -1954,9 +2394,9 @@ } }, "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", "license": "MIT", "dependencies": { "humanize-ms": "^1.2.1" @@ -2007,20 +2447,20 @@ } }, "node_modules/apify": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/apify/-/apify-3.2.6.tgz", - "integrity": "sha512-Uh8vWFb+hv6R2aPSol6QTFbUAdhRtXsVut7Cc0c/C8BbcNOqJlU2RY4xsw8clmc0fW/1UCIxMJxNRfbYnaelXQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/apify/-/apify-3.4.0.tgz", + "integrity": "sha512-jVxyujEpZq9XnKJQnqH9PHIC4MlQqXbXlhdgvM/LOcnvtVdVJCbfXgyYZFOARgeX+Asc47uv9s66v23fDoc0AA==", "license": "Apache-2.0", "dependencies": { "@apify/consts": "^2.23.0", "@apify/input_secrets": "^1.1.40", "@apify/log": "^2.4.3", "@apify/timeout": "^0.3.0", - "@apify/utilities": "^2.9.3", - "@crawlee/core": "^3.9.0", - "@crawlee/types": "^3.9.0", - "@crawlee/utils": "^3.9.0", - "apify-client": "^2.9.0", + "@apify/utilities": "^2.13.0", + "@crawlee/core": "^3.13.0", + "@crawlee/types": "^3.13.0", + "@crawlee/utils": "^3.13.0", + "apify-client": "^2.12.1", "fs-extra": "^11.2.0", "ow": "^0.28.2", "semver": "^7.5.4", @@ -2032,12 +2472,12 @@ } }, "node_modules/apify-client": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/apify-client/-/apify-client-2.12.0.tgz", - "integrity": "sha512-h04rPVft8tNjnwZswqF2k46bdHZWsDsfOE8PkmklZ9+/s/mb/Q/dMOXCx0u2+RTc8QoAkYS9LYs97wZyUWpoag==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/apify-client/-/apify-client-2.12.2.tgz", + "integrity": "sha512-+eSexDukVso58MQ8pOJj67mnaDkexH80VJs0/stfM8yNSUKMa/BIIdbG3rX8axjpTtT3UzpPgMIz6qh8inxFCQ==", "license": "Apache-2.0", "dependencies": { - "@apify/consts": "^2.25.0", + "@apify/consts": "^2.40.0", "@apify/log": "^2.2.6", "@crawlee/types": "^3.3.0", "agentkeepalive": "^4.2.1", @@ -2049,6 +2489,18 @@ "type-fest": "^4.0.0" } }, + "node_modules/apify/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2101,18 +2553,19 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2186,10 +2639,21 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/async-retry": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", @@ -2222,9 +2686,9 @@ } }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -2299,12 +2763,14 @@ "license": "ISC" }, "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==", + "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" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -2321,9 +2787,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", - "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "funding": [ { "type": "opencollective", @@ -2366,6 +2832,7 @@ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2417,9 +2884,9 @@ } }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "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", @@ -2430,13 +2897,13 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -2455,9 +2922,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001690", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", - "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "version": "1.0.30001713", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz", + "integrity": "sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==", "funding": [ { "type": "opencollective", @@ -2479,6 +2946,7 @@ "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, + "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", @@ -2512,10 +2980,32 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 16" } }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, "node_modules/cheerio-select": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", @@ -2615,11 +3105,23 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "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", + "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==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -2719,21 +3221,13 @@ } }, "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==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "ms": "^2.1.1" } }, "node_modules/decompress-response": { @@ -2768,6 +3262,7 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2907,9 +3402,9 @@ } }, "node_modules/domutils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.1.tgz", - "integrity": "sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", @@ -2936,9 +3431,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -2975,9 +3470,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.76", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", - "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", + "version": "1.5.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.137.tgz", + "integrity": "sha512-/QSJaU2JyIuTbbABAo/crOs+SuAZLS+fVVS10PVrIT9hrRkmZl8Hb0xPSkKRUUWHQtYzXHpQUW3Dy5hwMzGZkA==", "license": "ISC" }, "node_modules/encodeurl": { @@ -3002,9 +3497,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.8", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.8.tgz", - "integrity": "sha512-lfab8IzDn6EpI1ibZakcgS6WsfEBiB+43cuJo+wgylx1xKXf+Sp+YR3vFuQwC/u3sxYwV8Cxe3B0DpVUu/WiJQ==", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "dev": true, "license": "MIT", "dependencies": { @@ -3019,10 +3514,11 @@ "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", + "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.6", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", @@ -3043,11 +3539,12 @@ "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", - "own-keys": "^1.0.0", + "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", @@ -3087,12 +3584,13 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "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" @@ -3102,28 +3600,31 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, + "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": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/es-to-primitive": { @@ -3145,9 +3646,9 @@ } }, "node_modules/esbuild": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", - "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3158,30 +3659,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.1", - "@esbuild/android-arm": "0.23.1", - "@esbuild/android-arm64": "0.23.1", - "@esbuild/android-x64": "0.23.1", - "@esbuild/darwin-arm64": "0.23.1", - "@esbuild/darwin-x64": "0.23.1", - "@esbuild/freebsd-arm64": "0.23.1", - "@esbuild/freebsd-x64": "0.23.1", - "@esbuild/linux-arm": "0.23.1", - "@esbuild/linux-arm64": "0.23.1", - "@esbuild/linux-ia32": "0.23.1", - "@esbuild/linux-loong64": "0.23.1", - "@esbuild/linux-mips64el": "0.23.1", - "@esbuild/linux-ppc64": "0.23.1", - "@esbuild/linux-riscv64": "0.23.1", - "@esbuild/linux-s390x": "0.23.1", - "@esbuild/linux-x64": "0.23.1", - "@esbuild/netbsd-x64": "0.23.1", - "@esbuild/openbsd-arm64": "0.23.1", - "@esbuild/openbsd-x64": "0.23.1", - "@esbuild/sunos-x64": "0.23.1", - "@esbuild/win32-arm64": "0.23.1", - "@esbuild/win32-ia32": "0.23.1", - "@esbuild/win32-x64": "0.23.1" + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" } }, "node_modules/escalade": { @@ -3213,22 +3715,23 @@ } }, "node_modules/eslint": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", - "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", + "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.9.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.17.0", - "@eslint/plugin-kit": "^0.2.3", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.24.0", + "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", + "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", @@ -3236,7 +3739,7 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", + "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", @@ -3292,16 +3795,6 @@ "eslint-plugin-import": "^2.25.2" } }, - "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -3314,16 +3807,6 @@ "resolve": "^1.22.4" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/eslint-module-utils": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", @@ -3342,16 +3825,6 @@ } } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/eslint-plugin-import": { "version": "2.31.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", @@ -3386,56 +3859,22 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/eslint-plugin-import/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==", + "node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "peerDependencies": { + "eslint": ">=5.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "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": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/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-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", - "dev": true, - "license": "BSD-2-Clause", + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -3477,15 +3916,22 @@ "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==", + "node_modules/eslint/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==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/eslint/node_modules/json-schema-traverse": { @@ -3495,19 +3941,6 @@ "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", @@ -3567,6 +4000,7 @@ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } @@ -3616,33 +4050,32 @@ } }, "node_modules/eventsource": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.2.tgz", - "integrity": "sha512-YolzkJNxsTL3tCJMWFxpxtG2sCjbZ4LQUBUrkdaJK0ub0p6lmJt+2+1SwhKjLc652lpH9L/79Ptez972H9tphw==", - "dev": true, + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.6.tgz", + "integrity": "sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==", "license": "MIT", "dependencies": { - "eventsource-parser": "^3.0.0" + "eventsource-parser": "^3.0.1" }, "engines": { "node": ">=18.0.0" } }, "node_modules/eventsource-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", - "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", - "dev": true, + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz", + "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==", "license": "MIT", "engines": { "node": ">=18.0.0" } }, "node_modules/expect-type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz", - "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", + "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.0.0" } @@ -3693,6 +4126,21 @@ "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", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": "^4.11 || 5 || ^5.0.0-beta.1" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3715,9 +4163,9 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "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": { @@ -3725,7 +4173,7 @@ "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -3759,21 +4207,37 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", - "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "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.18.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", - "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "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/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -3788,15 +4252,15 @@ } }, "node_modules/file-type": { - "version": "19.6.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-19.6.0.tgz", - "integrity": "sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ==", + "version": "20.4.1", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-20.4.1.tgz", + "integrity": "sha512-hw9gNZXUfZ02Jo0uafWLaFVPter5/k2rfcrjFJJHX/77xtSDOfJuEFb6oKlFV86FLP1SuyHMW1PSk0U9M5tKkQ==", "license": "MIT", "dependencies": { - "get-stream": "^9.0.1", - "strtok3": "^9.0.1", + "@tokenizer/inflate": "^0.2.6", + "strtok3": "^10.2.0", "token-types": "^6.0.0", - "uint8array-extras": "^1.3.0" + "uint8array-extras": "^1.4.0" }, "engines": { "node": ">=18" @@ -3883,9 +4347,9 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "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" }, @@ -3910,23 +4374,30 @@ } }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" }, "engines": { @@ -3934,13 +4405,11 @@ } }, "node_modules/form-data-encoder": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz", - "integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==", - "license": "MIT", - "engines": { - "node": ">= 18" - } + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "dev": true, + "license": "MIT" }, "node_modules/formdata-node": { "version": "4.4.1", @@ -3981,9 +4450,9 @@ "license": "MIT" }, "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -4050,9 +4519,9 @@ } }, "node_modules/generative-bayesian-network": { - "version": "2.1.61", - "resolved": "https://registry.npmjs.org/generative-bayesian-network/-/generative-bayesian-network-2.1.61.tgz", - "integrity": "sha512-eIcVAU5I3SHKDwSqQxan6sRGAC0PRgj6rVNGUoKcErtAlbMsO8fr4Wr0hcBzLAc+6YKeNRpUKXWkEo/q1RLvTg==", + "version": "2.1.63", + "resolved": "https://registry.npmjs.org/generative-bayesian-network/-/generative-bayesian-network-2.1.63.tgz", + "integrity": "sha512-nH1t4R9nlWSmvFoI4DEcpXd0+yoGZcySVuUBkXhR09/Mf7O9AWFmR8lWqVGIoxpBS0WRNpV/qj4swKGGQAxAPQ==", "license": "Apache-2.0", "dependencies": { "adm-zip": "^0.5.9", @@ -4060,21 +4529,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", - "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", + "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.1", - "dunder-proto": "^1.0.0", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.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.0.0" + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4083,6 +4552,19 @@ "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/get-stream": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", @@ -4118,9 +4600,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", - "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "dev": true, "license": "MIT", "dependencies": { @@ -4144,9 +4626,9 @@ } }, "node_modules/globals": { - "version": "15.14.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", - "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, "license": "MIT", "engines": { @@ -4186,9 +4668,9 @@ } }, "node_modules/got": { - "version": "14.4.5", - "resolved": "https://registry.npmjs.org/got/-/got-14.4.5.tgz", - "integrity": "sha512-sq+uET8TnNKRNnjEOPJzMcxeI0irT8BBNmf+GtZcJpmhYsQM1DSKmCROUjPWKsXZ5HzwD5Cf5/RV+QD9BSTxJg==", + "version": "14.4.7", + "resolved": "https://registry.npmjs.org/got/-/got-14.4.7.tgz", + "integrity": "sha512-DI8zV1231tqiGzOiOzQWDhsBmncFW7oQDH6Zgy6pDPrqJuVZMtoSgPLLsBZQj8Jg4JFfwoOsDA8NGtLQLnIx2g==", "license": "MIT", "dependencies": { "@sindresorhus/is": "^7.0.1", @@ -4211,9 +4693,9 @@ } }, "node_modules/got-scraping": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/got-scraping/-/got-scraping-4.0.8.tgz", - "integrity": "sha512-QCptrUWsxgtP8LAnGZqjuJMwbLELlst1DF/Ba30OUOk7wi/LJtNwuYPUxoielRxTxd9QQ38FL/CWyRVc7m7ZkQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/got-scraping/-/got-scraping-4.1.1.tgz", + "integrity": "sha512-MbT+NMMU4VgvOg2tFIPOSIrMfH986fm0LJ17RxBLKlyTs3gh3xIMETpe+zdPaXY7tH1j6YYeqtfG0TnVMx6V2g==", "license": "Apache-2.0", "dependencies": { "got": "^14.2.1", @@ -4298,6 +4780,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/got/node_modules/form-data-encoder": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz", + "integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -4379,7 +4870,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -4404,13 +4894,13 @@ } }, "node_modules/header-generator": { - "version": "2.1.61", - "resolved": "https://registry.npmjs.org/header-generator/-/header-generator-2.1.61.tgz", - "integrity": "sha512-jwTzKvIeTcm4ghHSeQeHwdUGLuWqLg3zrOkt+Dsrr+NeuHtLlDdtisgNkpKn2yjJ2OAakwxmKWC41SNkEH0/5w==", + "version": "2.1.63", + "resolved": "https://registry.npmjs.org/header-generator/-/header-generator-2.1.63.tgz", + "integrity": "sha512-dicAWZb/zXmI3fPuCw1Ra1sTTC9x9cc5EOhwugmI/keXnRc3BzxDQTGHge+MeAdqhpo2ZOFTEV6u08lXJUA2uQ==", "license": "Apache-2.0", "dependencies": { "browserslist": "^4.21.1", - "generative-bayesian-network": "^2.1.61", + "generative-bayesian-network": "^2.1.63", "ow": "^0.28.1", "tslib": "^2.4.0" }, @@ -4418,6 +4908,25 @@ "node": ">=16.0.0" } }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -4517,9 +5026,9 @@ } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "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": { @@ -4592,13 +5101,17 @@ } }, "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4624,13 +5137,13 @@ } }, "node_modules/is-boolean-object": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", - "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", + "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" }, "engines": { @@ -4731,13 +5244,16 @@ } }, "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4808,6 +5324,12 @@ "node": ">=8" } }, + "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" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -4933,13 +5455,13 @@ } }, "node_modules/is-weakref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", - "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -4976,7 +5498,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/js-yaml": { @@ -5084,6 +5605,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", "license": "MIT" }, "node_modules/lodash.merge": { @@ -5097,7 +5619,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lowercase-keys": { "version": "3.0.0", @@ -5116,6 +5639,7 @@ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -5231,25 +5755,22 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "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": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5262,9 +5783,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", - "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -5272,6 +5793,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5366,10 +5888,19 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "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", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -5410,15 +5941,16 @@ } }, "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "es-object-atoms": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -5489,6 +6021,15 @@ "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", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -5658,7 +6199,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5681,13 +6221,15 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pathval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 14.16" } @@ -5705,12 +6247,12 @@ } }, "node_modules/peek-readable": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.3.1.tgz", - "integrity": "sha512-GVlENSDW6KHaXcd9zkZltB7tCLosKB/4Hg0fqBJkAoBgYG2Tn1xtMgXtSUuMU9AK/gCm/tTdT8mgAeF4YNeeqw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-7.0.0.tgz", + "integrity": "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ==", "license": "MIT", "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "type": "github", @@ -5736,10 +6278,19 @@ "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", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, "license": "MIT", "engines": { @@ -5765,6 +6316,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -5870,9 +6422,9 @@ "license": "MIT" }, "node_modules/quick-lru": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.0.tgz", - "integrity": "sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.1.tgz", + "integrity": "sha512-kLjThirJMkWKutUKbZ8ViqFc09tDQhlbQo2MNuVeLWbRauqYP96Sm6nzlQ24F0HFjUNZ4i9+AgldJ9H6DZXi7g==", "license": "MIT", "engines": { "node": ">=18" @@ -5918,19 +6470,19 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz", - "integrity": "sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "dunder-proto": "^1.0.1", - "es-abstract": "^1.23.6", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" }, "engines": { @@ -5941,15 +6493,17 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", - "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", "set-function-name": "^2.0.2" }, "engines": { @@ -6040,9 +6594,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -6060,12 +6614,13 @@ } }, "node_modules/rollup": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", - "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", + "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -6075,54 +6630,97 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.35.0", - "@rollup/rollup-android-arm64": "4.35.0", - "@rollup/rollup-darwin-arm64": "4.35.0", - "@rollup/rollup-darwin-x64": "4.35.0", - "@rollup/rollup-freebsd-arm64": "4.35.0", - "@rollup/rollup-freebsd-x64": "4.35.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", - "@rollup/rollup-linux-arm-musleabihf": "4.35.0", - "@rollup/rollup-linux-arm64-gnu": "4.35.0", - "@rollup/rollup-linux-arm64-musl": "4.35.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", - "@rollup/rollup-linux-riscv64-gnu": "4.35.0", - "@rollup/rollup-linux-s390x-gnu": "4.35.0", - "@rollup/rollup-linux-x64-gnu": "4.35.0", - "@rollup/rollup-linux-x64-musl": "4.35.0", - "@rollup/rollup-win32-arm64-msvc": "4.35.0", - "@rollup/rollup-win32-ia32-msvc": "4.35.0", - "@rollup/rollup-win32-x64-msvc": "4.35.0", + "@rollup/rollup-android-arm-eabi": "4.40.0", + "@rollup/rollup-android-arm64": "4.40.0", + "@rollup/rollup-darwin-arm64": "4.40.0", + "@rollup/rollup-darwin-x64": "4.40.0", + "@rollup/rollup-freebsd-arm64": "4.40.0", + "@rollup/rollup-freebsd-x64": "4.40.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", + "@rollup/rollup-linux-arm-musleabihf": "4.40.0", + "@rollup/rollup-linux-arm64-gnu": "4.40.0", + "@rollup/rollup-linux-arm64-musl": "4.40.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-musl": "4.40.0", + "@rollup/rollup-linux-s390x-gnu": "4.40.0", + "@rollup/rollup-linux-x64-gnu": "4.40.0", + "@rollup/rollup-linux-x64-musl": "4.40.0", + "@rollup/rollup-win32-arm64-msvc": "4.40.0", + "@rollup/rollup-win32-ia32-msvc": "4.40.0", + "@rollup/rollup-win32-x64-msvc": "4.40.0", "fsevents": "~2.3.2" } }, - "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" - } - ], + "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", "dependencies": { - "queue-microtask": "^1.2.2" + "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/safe-array-concat": { - "version": "1.1.3", + "node_modules/router/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/router/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", + "engines": { + "node": ">=16" + } + }, + "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-array-concat": { + "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, @@ -6209,15 +6807,13 @@ "license": "ISC" }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/send": { @@ -6317,6 +6913,21 @@ "node": ">= 0.4" } }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -6327,7 +6938,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -6340,7 +6950,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6422,7 +7031,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/signal-exit": { "version": "3.0.7", @@ -6435,6 +7045,7 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -6455,7 +7066,8 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/statuses": { "version": "2.0.1", @@ -6467,10 +7079,11 @@ } }, "node_modules/std-env": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz", - "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==", - "dev": true + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" }, "node_modules/stream-chain": { "version": "2.2.5", @@ -6579,16 +7192,16 @@ } }, "node_modules/strtok3": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-9.1.1.tgz", - "integrity": "sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.2.2.tgz", + "integrity": "sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg==", "license": "MIT", "dependencies": { "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.3.1" + "peek-readable": "^7.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "type": "github", @@ -6628,9 +7241,9 @@ "license": "MIT" }, "node_modules/tiktoken": { - "version": "1.0.18", - "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.18.tgz", - "integrity": "sha512-DXJesdYwmBHtkmz1sji+UMZ4AOEE8F7Uw/PS/uy0XfkKOzZC4vXkYXHMYyDT+grdflvF4bggtPt9cYaqOMslBw==", + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.20.tgz", + "integrity": "sha512-zVIpXp84kth/Ni2me1uYlJgl2RZ2EjxwDaWLeDY/s6fZiyO9n1QoTOM5P7ZSYfToPvAvwYNMbg5LETVYVKyzfQ==", "dev": true, "license": "MIT" }, @@ -6638,19 +7251,22 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tinypool": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" } @@ -6660,6 +7276,7 @@ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -6669,26 +7286,27 @@ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/tldts": { - "version": "6.1.70", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.70.tgz", - "integrity": "sha512-/W1YVgYVJd9ZDjey5NXadNh0mJXkiUMUue9Zebd0vpdo1sU+H4zFFTaJ1RKD4N6KFoHfcXy6l+Vu7bh+bdWCzA==", + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", "license": "MIT", "dependencies": { - "tldts-core": "^6.1.70" + "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.70", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.70.tgz", - "integrity": "sha512-RNnIXDB1FD4T9cpQRErEqw6ZpjLlGdMOitdV+0xtbsnwr4YFka1zpc7D4KD+aAn8oSG5JyFrdasZTE04qDE9Yg==", + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", "license": "MIT" }, "node_modules/to-regex-range": { @@ -6731,9 +7349,9 @@ } }, "node_modules/tough-cookie": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", - "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", "license": "BSD-3-Clause", "dependencies": { "tldts": "^6.1.32" @@ -6750,16 +7368,16 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "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": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/tsconfig-paths": { @@ -6795,13 +7413,13 @@ "license": "0BSD" }, "node_modules/tsx": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", - "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", + "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.23.0", + "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -6828,9 +7446,9 @@ } }, "node_modules/type-fest": { - "version": "4.31.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.31.0.tgz", - "integrity": "sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.0.tgz", + "integrity": "sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -6931,9 +7549,9 @@ } }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "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": { @@ -6945,15 +7563,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.2.tgz", - "integrity": "sha512-KuXezG6jHkvC3MvizeXgupZzaG5wjhU3yE8E7e6viOvAvD9xAWYp8/vy0WULTGe9DYDWcQu7aW03YIV3mSitrQ==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.30.1.tgz", + "integrity": "sha512-D7lC0kcehVH7Mb26MRQi64LMyRJsj3dToJxM1+JVTl53DQSV5/7oUGWQLcKl1C1KnoVHxMMU2FNQMffr7F3Row==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.18.2", - "@typescript-eslint/parser": "8.18.2", - "@typescript-eslint/utils": "8.18.2" + "@typescript-eslint/eslint-plugin": "8.30.1", + "@typescript-eslint/parser": "8.30.1", + "@typescript-eslint/utils": "8.30.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6964,7 +7582,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/uint8array-extras": { @@ -6999,9 +7617,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": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, "node_modules/universalify": { @@ -7023,9 +7641,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "funding": [ { "type": "opencollective", @@ -7043,7 +7661,7 @@ "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -7090,10 +7708,11 @@ } }, "node_modules/vite": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz", - "integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==", + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz", + "integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", @@ -7161,10 +7780,11 @@ } }, "node_modules/vite-node": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.8.tgz", - "integrity": "sha512-6PhR4H9VGlcwXZ+KWCdMqbtG649xCPZqfI9j2PsK1FcXgEzro5bGHcVKFCTqPLaNKZES8Evqv4LwvZARsq5qlg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.1.1.tgz", + "integrity": "sha512-V+IxPAE2FvXpTCHXyNem0M+gWm6J7eRyWPR6vYoG/Gl+IscNOjXzztUhimQgTxaAoUoj40Qqimaa0NLIOOAH4w==", "dev": true, + "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", @@ -7182,455 +7802,50 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", - "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", - "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", - "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", - "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", - "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", - "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", - "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", - "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", - "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", - "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", - "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", - "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", - "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", - "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", - "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", - "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", - "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", - "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", - "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", - "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", - "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", - "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", - "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", - "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", - "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "node_modules/vite-node/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==", "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" }, "engines": { - "node": ">=18" + "node": ">=6.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.1", - "@esbuild/android-arm": "0.25.1", - "@esbuild/android-arm64": "0.25.1", - "@esbuild/android-x64": "0.25.1", - "@esbuild/darwin-arm64": "0.25.1", - "@esbuild/darwin-x64": "0.25.1", - "@esbuild/freebsd-arm64": "0.25.1", - "@esbuild/freebsd-x64": "0.25.1", - "@esbuild/linux-arm": "0.25.1", - "@esbuild/linux-arm64": "0.25.1", - "@esbuild/linux-ia32": "0.25.1", - "@esbuild/linux-loong64": "0.25.1", - "@esbuild/linux-mips64el": "0.25.1", - "@esbuild/linux-ppc64": "0.25.1", - "@esbuild/linux-riscv64": "0.25.1", - "@esbuild/linux-s390x": "0.25.1", - "@esbuild/linux-x64": "0.25.1", - "@esbuild/netbsd-arm64": "0.25.1", - "@esbuild/netbsd-x64": "0.25.1", - "@esbuild/openbsd-arm64": "0.25.1", - "@esbuild/openbsd-x64": "0.25.1", - "@esbuild/sunos-x64": "0.25.1", - "@esbuild/win32-arm64": "0.25.1", - "@esbuild/win32-ia32": "0.25.1", - "@esbuild/win32-x64": "0.25.1" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/vitest": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.8.tgz", - "integrity": "sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==", - "dev": true, - "dependencies": { - "@vitest/expect": "3.0.8", - "@vitest/mocker": "3.0.8", - "@vitest/pretty-format": "^3.0.8", - "@vitest/runner": "3.0.8", - "@vitest/snapshot": "3.0.8", - "@vitest/spy": "3.0.8", - "@vitest/utils": "3.0.8", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.1.1.tgz", + "integrity": "sha512-kiZc/IYmKICeBAZr9DQ5rT7/6bD9G7uqQEki4fxazi1jdVl2mWGzedtBs5s6llz59yQhVb7FFY2MbHzHCnT79Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "3.1.1", + "@vitest/mocker": "3.1.1", + "@vitest/pretty-format": "^3.1.1", + "@vitest/runner": "3.1.1", + "@vitest/snapshot": "3.1.1", + "@vitest/spy": "3.1.1", + "@vitest/utils": "3.1.1", "chai": "^5.2.0", "debug": "^4.4.0", - "expect-type": "^1.1.0", + "expect-type": "^1.2.0", "magic-string": "^0.30.17", "pathe": "^2.0.3", - "std-env": "^3.8.0", + "std-env": "^3.8.1", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.8", + "vite-node": "3.1.1", "why-is-node-running": "^2.3.0" }, "bin": { @@ -7646,8 +7861,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.8", - "@vitest/ui": "3.0.8", + "@vitest/browser": "3.1.1", + "@vitest/ui": "3.1.1", "happy-dom": "*", "jsdom": "*" }, @@ -7675,6 +7890,24 @@ } } }, + "node_modules/vitest/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/web-streams-polyfill": { "version": "4.0.0-beta.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", @@ -7716,7 +7949,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -7796,16 +8028,17 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", - "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "for-each": "^0.3.3", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, @@ -7821,6 +8054,7 @@ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, + "license": "MIT", "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" @@ -7842,10 +8076,16 @@ "node": ">=0.10.0" } }, + "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" + }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -7863,15 +8103,6 @@ } } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -7886,17 +8117,19 @@ } }, "node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz", - "integrity": "sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==", + "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", "peerDependencies": { "zod": "^3.24.1" } diff --git a/package.json b/package.json index cd14f9c0..c67e91c5 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,13 @@ "name": "@apify/actors-mcp-server", "version": "0.1.23", "type": "module", - "description": "Model Context Protocol Server for Apify Actors", + "description": "Model Context Protocol Server for Apify", "engines": { "node": ">=18.0.0" }, "main": "dist/index.js", "bin": { - "actors-mcp-server": "./dist/index.js" + "actors-mcp-server": "./dist/stdio.js" }, "files": [ "dist", @@ -30,29 +30,30 @@ "model context protocol" ], "dependencies": { - "@modelcontextprotocol/sdk": "^1.3.1", + "@apify/log": "^2.5.16", + "@modelcontextprotocol/sdk": "github:jirispilka/mcp-typescript-sdk#fix/add-src-dir", "ajv": "^8.17.1", - "apify": "^3.2.6", - "apify-client": "^2.11.2", + "apify": "^3.4.0", + "apify-client": "^2.12.1", "express": "^4.21.2", - "yargs-parser": "^21.1.1", + "minimist": "^1.2.8", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.1" }, "devDependencies": { "@anthropic-ai/sdk": "^0.33.1", "@anthropic-ai/tokenizer": "^0.0.4", - "@apify/eslint-config": "^0.5.0-beta.2", + "@apify/eslint-config": "^1.0.0", "@apify/tsconfig": "^0.1.0", "@types/express": "^4.0.0", "@types/minimist": "^1.2.5", "@types/yargs-parser": "^21.0.3", "dotenv": "^16.4.7", - "eslint": "^9.17.0", + "eslint": "^9.19.0", "eventsource": "^3.0.2", "tsx": "^4.6.2", "typescript": "^5.3.3", - "typescript-eslint": "^8.18.2", + "typescript-eslint": "^8.23.0", "vitest": "^3.0.8" }, "scripts": { @@ -61,10 +62,12 @@ "start:dev": "tsx src/main.ts", "lint": "eslint .", "lint:fix": "eslint . --fix", - "build": "tsc", - "watch": "tsc --watch", - "inspector": "npx @modelcontextprotocol/inspector dist/index.js", - "test": "vitest run" + "build": "tsc -b src", + "build:watch": "tsc -b src -w", + "type-check": "tsc --noEmit", + "inspector": "npm run build && npx @modelcontextprotocol/inspector dist/stdio.js", + "test": "vitest run", + "clean": "tsc -b src --clean" }, "author": "Apify", "license": "MIT" diff --git a/src/actor/README.md b/src/actor/README.md new file mode 100644 index 00000000..6c32ec58 --- /dev/null +++ b/src/actor/README.md @@ -0,0 +1,6 @@ +# Actor + +Code related to Apify Actor called Actors-MCP-Server. +This Actor will be deprecated in favor of Apify MCP Server, therefore we are keeping it separate from the main codebase. + +The only exception is the `src/main.ts` file that also belongs to the Actor. diff --git a/src/actor/const.ts b/src/actor/const.ts new file mode 100644 index 00000000..bc9aa114 --- /dev/null +++ b/src/actor/const.ts @@ -0,0 +1,18 @@ +/** + * Constants for the Actor. + */ +export const HEADER_READINESS_PROBE = 'x-apify-container-server-readiness-probe'; + +export enum Routes { + ROOT = '/', + MCP = '/mcp', + SSE = '/sse', + MESSAGE = '/message', +} + +export const getHelpMessage = (host: string) => `To interact with the server you can either: +- send request to ${host}${Routes.MCP}?token=YOUR-APIFY-TOKEN and receive a response +or +- connect for Server-Sent Events (SSE) via GET request to: ${host}${Routes.SSE}?token=YOUR-APIFY-TOKEN +- send messages via POST request to: ${host}${Routes.MESSAGE}?token=YOUR-APIFY-TOKEN + (Include your message content in the request body.)`; diff --git a/src/actor/server.ts b/src/actor/server.ts new file mode 100644 index 00000000..b71140ae --- /dev/null +++ b/src/actor/server.ts @@ -0,0 +1,174 @@ +/* + * Express server implementation used for standby Actor mode. + */ + +import { randomUUID } from 'node:crypto'; + +import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import type { Request, Response } from 'express'; +import express from 'express'; + +import log from '@apify/log'; + +import { type ActorsMcpServer } from '../mcp/server.js'; +import { processParamsGetTools } from '../mcp/utils.js'; +import { getHelpMessage, HEADER_READINESS_PROBE, Routes } from './const.js'; +import { getActorRunData } from './utils.js'; + +export function createExpressApp( + host: string, + mcpServer: ActorsMcpServer, +): express.Express { + const app = express(); + let transportSSE: SSEServerTransport; + const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {}; + + function respondWithError(res: Response, error: unknown, logMessage: string, statusCode = 500) { + log.error(`${logMessage}: ${error}`); + if (!res.headersSent) { + res.status(statusCode).json({ + jsonrpc: '2.0', + error: { + code: statusCode === 500 ? -32603 : -32000, + message: statusCode === 500 ? 'Internal server error' : 'Bad Request', + }, + id: null, + }); + } + } + + app.get(Routes.ROOT, async (req: Request, res: Response) => { + if (req.headers && req.get(HEADER_READINESS_PROBE) !== undefined) { + log.debug('Received readiness probe'); + res.status(200).json({ message: 'Server is ready' }).end(); + return; + } + try { + log.info(`Received GET message at: ${Routes.ROOT}`); + const tools = await processParamsGetTools(req.url, process.env.APIFY_TOKEN as string); + if (tools) { + mcpServer.updateTools(tools); + } + res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-cache'); + res.setHeader('Connection', 'keep-alive'); + res.status(200).json({ message: `Actor is using Model Context Protocol. ${getHelpMessage(host)}`, data: getActorRunData() }).end(); + } catch (error) { + respondWithError(res, error, `Error in GET ${Routes.ROOT}`); + } + }); + + app.head(Routes.ROOT, (_req: Request, res: Response) => { + res.status(200).end(); + }); + + app.get(Routes.SSE, async (req: Request, res: Response) => { + try { + log.info(`Received GET message at: ${Routes.SSE}`); + const tools = await processParamsGetTools(req.url, process.env.APIFY_TOKEN as string); + if (tools.length > 0) { + mcpServer.updateTools(tools); + } else { + // We are loading default Actors (if not specified otherwise), so that we don't have "empty" tools + await mcpServer.loadDefaultTools(process.env.APIFY_TOKEN as string); + } + transportSSE = new SSEServerTransport(Routes.MESSAGE, res); + await mcpServer.connect(transportSSE); + } catch (error) { + respondWithError(res, error, `Error in GET ${Routes.SSE}`); + } + }); + + app.post(Routes.MESSAGE, async (req: Request, res: Response) => { + try { + log.info(`Received POST message at: ${Routes.MESSAGE}`); + if (transportSSE) { + await transportSSE.handlePostMessage(req, res); + } else { + log.error('Server is not connected to the client.'); + res.status(400).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Bad Request: Server is not connected to the client. ' + + 'Connect to the server with GET request to /sse endpoint', + }, + id: null, + }); + } + } catch (error) { + respondWithError(res, error, `Error in POST ${Routes.MESSAGE}`); + } + }); + + app.post(Routes.MCP, async (req: Request, res: Response) => { + log.info('Received MCP request:', req.body); + try { + // Check for existing session ID + const sessionId = req.headers['mcp-session-id'] as string | undefined; + let transport: StreamableHTTPServerTransport; + + if (sessionId && transports[sessionId]) { + // Reuse existing transport + transport = transports[sessionId]; + } else if (!sessionId && isInitializeRequest(req.body)) { + // New initialization request - use JSON response mode + transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID(), + enableJsonResponse: true, // Enable JSON response mode + }); + + // Connect the transport to the MCP server BEFORE handling the request + await mcpServer.connect(transport); + + // After handling the request, if we get a session ID back, store the transport + await transport.handleRequest(req, res, req.body); + + // Store the transport by session ID for future requests + if (transport.sessionId) { + transports[transport.sessionId] = transport; + } + return; // Already handled + } else { + // Invalid request - no session ID or not initialization request + res.status(400).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Bad Request: No valid session ID provided or not initialization request', + }, + id: null, + }); + return; + } + + // Handle the request with existing transport - no need to reconnect + await transport.handleRequest(req, res, req.body); + } catch (error) { + respondWithError(res, error, 'Error handling MCP request'); + } + }); + + // Handle GET requests for SSE streams according to spec + app.get(Routes.MCP, async (_req: Request, res: Response) => { + // We don't support GET requests for this server + // The spec requires returning 405 Method Not Allowed in this case + res.status(405).set('Allow', 'POST').send('Method Not Allowed'); + }); + + // Catch-all for undefined routes + app.use((req: Request, res: Response) => { + res.status(404).json({ message: `There is nothing at route ${req.method} ${req.originalUrl}. ${getHelpMessage(host)}` }).end(); + }); + + return app; +} + +// Helper function to detect initialize requests +function isInitializeRequest(body: unknown): boolean { + if (Array.isArray(body)) { + return body.some((msg) => typeof msg === 'object' && msg !== null && 'method' in msg && msg.method === 'initialize'); + } + return typeof body === 'object' && body !== null && 'method' in body && body.method === 'initialize'; +} diff --git a/src/actor/types.ts b/src/actor/types.ts new file mode 100644 index 00000000..00ca61d3 --- /dev/null +++ b/src/actor/types.ts @@ -0,0 +1,22 @@ +export interface ActorRunData { + id?: string; + actId?: string; + userId?: string; + startedAt?: string; + finishedAt: null; + status: 'RUNNING'; + meta: { + origin?: string; + }; + options: { + build?: string; + memoryMbytes?: string; + }; + buildId?: string; + defaultKeyValueStoreId?: string; + defaultDatasetId?: string; + defaultRequestQueueId?: string; + buildNumber?: string; + containerUrl?: string; + standbyUrl?: string; +} diff --git a/src/actor/utils.ts b/src/actor/utils.ts new file mode 100644 index 00000000..f4a2e80a --- /dev/null +++ b/src/actor/utils.ts @@ -0,0 +1,28 @@ +import { Actor } from 'apify'; + +import type { ActorRunData } from './types.js'; + +export function getActorRunData(): ActorRunData | null { + return Actor.isAtHome() ? { + id: process.env.ACTOR_RUN_ID, + actId: process.env.ACTOR_ID, + userId: process.env.APIFY_USER_ID, + startedAt: process.env.ACTOR_STARTED_AT, + finishedAt: null, + status: 'RUNNING', + meta: { + origin: process.env.APIFY_META_ORIGIN, + }, + options: { + build: process.env.ACTOR_BUILD_NUMBER, + memoryMbytes: process.env.ACTOR_MEMORY_MBYTES, + }, + buildId: process.env.ACTOR_BUILD_ID, + defaultKeyValueStoreId: process.env.ACTOR_DEFAULT_KEY_VALUE_STORE_ID, + defaultDatasetId: process.env.ACTOR_DEFAULT_DATASET_ID, + defaultRequestQueueId: process.env.ACTOR_DEFAULT_REQUEST_QUEUE_ID, + buildNumber: process.env.ACTOR_BUILD_NUMBER, + containerUrl: process.env.ACTOR_WEB_SERVER_URL, + standbyUrl: process.env.ACTOR_STANDBY_URL, + } : null; +} diff --git a/src/apify-client.ts b/src/apify-client.ts new file mode 100644 index 00000000..3543108b --- /dev/null +++ b/src/apify-client.ts @@ -0,0 +1,33 @@ +import type { ApifyClientOptions } from 'apify'; +import { ApifyClient as _ApifyClient } from 'apify-client'; +import type { AxiosRequestConfig } from 'axios'; + +import { USER_AGENT_ORIGIN } from './const.js'; + +/** + * Adds a User-Agent header to the request config. + * @param config + * @private + */ +function addUserAgent(config: AxiosRequestConfig): AxiosRequestConfig { + const updatedConfig = { ...config }; + updatedConfig.headers = updatedConfig.headers ?? {}; + updatedConfig.headers['User-Agent'] = `${updatedConfig.headers['User-Agent'] ?? ''}; ${USER_AGENT_ORIGIN}`; + return updatedConfig; +} + +export function getApifyAPIBaseUrl(): string { + // Workaround for Actor server where the platform APIFY_API_BASE_URL did not work with getActorDefinition from actors.ts + if (process.env.APIFY_IS_AT_HOME) return 'https://api.apify.com'; + return process.env.APIFY_API_BASE_URL || 'https://api.apify.com'; +} + +export class ApifyClient extends _ApifyClient { + constructor(options: ApifyClientOptions) { + super({ + ...options, + baseUrl: getApifyAPIBaseUrl(), + requestInterceptors: [addUserAgent], + }); + } +} diff --git a/src/const.ts b/src/const.ts index cb8f06f4..20decefe 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,10 +1,33 @@ +// Actor input const +export const ACTOR_README_MAX_LENGTH = 5_000; +export const ACTOR_ENUM_MAX_LENGTH = 200; +export const ACTOR_MAX_DESCRIPTION_LENGTH = 500; + +// Actor output const +export const ACTOR_OUTPUT_MAX_CHARS_PER_ITEM = 5_000; +export const ACTOR_OUTPUT_TRUNCATED_MESSAGE = `Output was truncated because it will not fit into context.` + + `There is no reason to call this tool again!`; + +export const ACTOR_ADDITIONAL_INSTRUCTIONS = 'Never call/execute tool/Actor unless confirmed by the user. ' + + 'Always limit the number of results in the call arguments.'; + +// Actor run const +export const ACTOR_MAX_MEMORY_MBYTES = 4_096; // If the Actor requires 8GB of memory, free users can't run actors-mcp-server and requested Actor + +// MCP Server export const SERVER_NAME = 'apify-mcp-server'; -export const SERVER_VERSION = '0.1.0'; +export const SERVER_VERSION = '1.0.0'; -export const HEADER_READINESS_PROBE = 'x-apify-container-server-readiness-probe'; -export const MAX_DESCRIPTION_LENGTH = 500; +// User agent headers export const USER_AGENT_ORIGIN = 'Origin/mcp-server'; +export enum HelperTools { + SEARCH = 'search', + ADD_TOOL = 'add-tool', + REMOVE_TOOL = 'remove-tool', + GET_TOOL_DETAILS = 'get-tool-details', +} + export const defaults = { actors: [ 'apify/instagram-scraper', @@ -15,23 +38,4 @@ export const defaults = { maxMemoryMbytes: 4096, }; -export const ACTOR_README_MAX_LENGTH = 5_000; -export const ACTOR_ENUM_MAX_LENGTH = 200; -export const ACTOR_OUTPUT_MAX_CHARS_PER_ITEM = 5_000; -export const ACTOR_OUTPUT_TRUNCATED_MESSAGE = `Output was truncated because it will not fit into context.` - + `There is no reason to call this tool again!`; -export const ACTOR_ADDITIONAL_INSTRUCTIONS = 'Never call/execute tool/Actor unless confirmed by the user. ' - + 'Always limit the number of results in the call arguments.'; - -export enum InternalTools { - DISCOVER_ACTORS = 'discover-actors', - ADD_ACTOR_TO_TOOLS = 'add-actor-to-tools', - REMOVE_ACTOR_FROM_TOOLS = 'remove-actor-from-tools', - GET_ACTOR_DETAILS = 'get-actor-details', -} - -export enum Routes { - ROOT = '/', - SSE = '/sse', - MESSAGE = '/message', -} +export const APIFY_USERNAME = 'apify'; diff --git a/src/examples/clientSse.ts b/src/examples/clientSse.ts index 765e2135..f5f7d930 100644 --- a/src/examples/clientSse.ts +++ b/src/examples/clientSse.ts @@ -6,16 +6,17 @@ * It requires the `APIFY_TOKEN` in the `.env` file. */ -import path from 'path'; -import { fileURLToPath } from 'url'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js'; -import dotenv from 'dotenv'; -import { EventSource } from 'eventsource'; +import dotenv from 'dotenv'; // eslint-disable-line import/no-extraneous-dependencies +import type { EventSourceInit } from 'eventsource'; +import { EventSource } from 'eventsource'; // eslint-disable-line import/no-extraneous-dependencies -import { actorNameToToolName } from '../actors.js'; +import { actorNameToToolName } from '../tools/utils.js'; const REQUEST_TIMEOUT = 120_000; // 2 minutes const filename = fileURLToPath(import.meta.url); @@ -23,18 +24,32 @@ const dirname = path.dirname(filename); dotenv.config({ path: path.resolve(dirname, '../../.env') }); -const SERVER_URL = 'https://actors-mcp-server.apify.actor/sse'; +const SERVER_URL = process.env.MCP_SERVER_URL_BASE || 'https://actors-mcp-server.apify.actor/sse'; // We need to change forward slash / to underscore -- in the tool name as Anthropic does not allow forward slashes in the tool name const SELECTED_TOOL = actorNameToToolName('apify/rag-web-browser'); -const QUERY = 'web browser for Anthropic'; +// const QUERY = 'web browser for Anthropic'; +const QUERY = 'apify'; if (!process.env.APIFY_TOKEN) { console.error('APIFY_TOKEN is required but not set in the environment variables.'); process.exit(1); } +// Declare EventSource on globalThis if not available (needed for Node.js environment) +declare global { + + // eslint-disable-next-line no-var, vars-on-top + var EventSource: { + new(url: string, eventSourceInitDict?: EventSourceInit): EventSource; + prototype: EventSource; + CONNECTING: 0; + OPEN: 1; + CLOSED: 2; + }; +} + if (typeof globalThis.EventSource === 'undefined') { - globalThis.EventSource = EventSource as unknown as typeof globalThis.EventSource; + globalThis.EventSource = EventSource; } async function main(): Promise { @@ -94,10 +109,11 @@ async function main(): Promise { } catch (error: unknown) { if (error instanceof Error) { console.error('Error:', error.message); - console.error(error.stack); } else { console.error('An unknown error occurred:', error); } + } finally { + await client.close(); } } diff --git a/src/examples/clientStdio.ts b/src/examples/clientStdio.ts index 468f007f..343e380e 100644 --- a/src/examples/clientStdio.ts +++ b/src/examples/clientStdio.ts @@ -6,23 +6,23 @@ * You can choose actors to run in the server, for example: `apify/rag-web-browser`. */ -import { execSync } from 'child_process'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import { execSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js'; -import dotenv from 'dotenv'; +import dotenv from 'dotenv'; // eslint-disable-line import/no-extraneous-dependencies -import { actorNameToToolName } from '../actors.js'; +import { actorNameToToolName } from '../tools/utils.js'; // Resolve dirname equivalent in ES module const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); dotenv.config({ path: path.resolve(dirname, '../../.env') }); -const SERVER_PATH = path.resolve(dirname, '../../dist/index.js'); +const SERVER_PATH = path.resolve(dirname, '../../dist/stdio.js'); const NODE_PATH = execSync(process.platform === 'win32' ? 'where node' : 'which node').toString().trim(); const TOOLS = 'apify/rag-web-browser,lukaskrivka/google-maps-with-contact-details'; diff --git a/src/examples/clientStdioChat.ts b/src/examples/clientStdioChat.ts index 1ebdf607..bd1118c9 100644 --- a/src/examples/clientStdioChat.ts +++ b/src/examples/clientStdioChat.ts @@ -17,17 +17,17 @@ * Let me summarize the key points: */ -import { execSync } from 'child_process'; -import path from 'path'; -import * as readline from 'readline'; -import { fileURLToPath } from 'url'; +import { execSync } from 'node:child_process'; +import path from 'node:path'; +import * as readline from 'node:readline'; +import { fileURLToPath } from 'node:url'; -import { Anthropic } from '@anthropic-ai/sdk'; -import type { Message, ToolUseBlock, MessageParam } from '@anthropic-ai/sdk/resources/messages'; +import { Anthropic } from '@anthropic-ai/sdk'; // eslint-disable-line import/no-extraneous-dependencies +import type { Message, MessageParam, ToolUseBlock } from '@anthropic-ai/sdk/resources/messages'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js'; -import dotenv from 'dotenv'; +import dotenv from 'dotenv'; // eslint-disable-line import/no-extraneous-dependencies const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); @@ -41,7 +41,7 @@ const MAX_TOKENS = 2048; // Maximum tokens for Claude response // const CLAUDE_MODEL = 'claude-3-5-haiku-20241022'; // a fastest model const CLAUDE_MODEL = 'claude-3-haiku-20240307'; // a fastest and most compact model for near-instant responsiveness const DEBUG = true; -const DEBUG_SERVER_PATH = path.resolve(dirname, '../../dist/index.js'); +const DEBUG_SERVER_PATH = path.resolve(dirname, '../../dist/stdio.js'); const NODE_PATH = execSync('which node').toString().trim(); diff --git a/src/examples/clientStreamableHttp.ts b/src/examples/clientStreamableHttp.ts new file mode 100644 index 00000000..2322dc78 --- /dev/null +++ b/src/examples/clientStreamableHttp.ts @@ -0,0 +1,109 @@ +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; +import type { CallToolRequest, ListToolsRequest } from '@modelcontextprotocol/sdk/types.js'; +import { + CallToolResultSchema, + ListToolsResultSchema, + LoggingMessageNotificationSchema, +} from '@modelcontextprotocol/sdk/types.js'; + +import log from '@apify/log'; + +log.setLevel(log.LEVELS.DEBUG); + +async function main(): Promise { + // Create a new client with streamable HTTP transport + const client = new Client({ + name: 'example-client', + version: '1.0.0', + }); + + const transport = new StreamableHTTPClientTransport( + new URL('http://localhost:3000/mcp'), + ); + + // Connect the client using the transport and initialize the server + await client.connect(transport); + log.debug('Connected to MCP server'); + + // Set up notification handlers for server-initiated messages + client.setNotificationHandler(LoggingMessageNotificationSchema, (notification) => { + log.debug(`Notification received: ${notification.params.level} - ${notification.params.data}`); + }); + + // List and call tools + await listTools(client); + + await callSearchTool(client); + await callActor(client); + + // Keep the connection open to receive notifications + log.debug('\nKeeping connection open to receive notifications. Press Ctrl+C to exit.'); +} + +async function listTools(client: Client): Promise { + try { + const toolsRequest: ListToolsRequest = { + method: 'tools/list', + params: {}, + }; + const toolsResult = await client.request(toolsRequest, ListToolsResultSchema); + log.debug(`Tools available, count: ${toolsResult.tools.length}`); + for (const tool of toolsResult.tools) { + log.debug(`Tool: ${tool.name}, Description: ${tool.description}`); + } + if (toolsResult.tools.length === 0) { + log.debug('No tools available from the server'); + } + } catch (error) { + log.error(`Tools not supported by this server (${error})`); + } +} + +async function callSearchTool(client: Client): Promise { + try { + const searchRequest: CallToolRequest = { + method: 'tools/call', + params: { + name: 'search', + arguments: { search: 'rag web browser', limit: 1 }, + }, + }; + const searchResult = await client.request(searchRequest, CallToolResultSchema); + log.debug('Search result:'); + searchResult.content.forEach((item) => { + if (item.type === 'text') { + log.debug(`\t${item.text}`); + } + }); + } catch (error) { + log.error(`Error calling greet tool: ${error}`); + } +} + +async function callActor(client: Client): Promise { + try { + log.debug('\nCalling Actor...'); + const actorRequest: CallToolRequest = { + method: 'tools/call', + params: { + name: 'apify/rag-web-browser', + arguments: { query: 'apify mcp server' }, + }, + }; + const actorResult = await client.request(actorRequest, CallToolResultSchema); + log.debug('Actor results:'); + actorResult.content.forEach((item) => { + if (item.type === 'text') { + log.debug(`- ${item.text}`); + } + }); + } catch (error) { + log.error(`Error calling Actor: ${error}`); + } +} + +main().catch((error: unknown) => { + log.error('Error running MCP client:', error as Error); + process.exit(1); +}); diff --git a/src/index.ts b/src/index.ts index 21ae3040..555d3645 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,59 +1,8 @@ -#!/usr/bin/env node -/** - * This script initializes and starts the Apify MCP server using the Stdio transport. - * - * Usage: - * node --actors= - * - * Command-line arguments: - * --actors - A comma-separated list of actor full names to add to the server. - * - * Example: - * node index.js --actors=apify/google-search-scraper,apify/instagram-scraper - */ +/* + This file provides essential functions and tools for MCP servers, serving as a library. + The ActorsMcpServer should be the only class exported from the package +*/ -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import parser from 'yargs-parser'; +import { ActorsMcpServer } from './mcp/server.js'; -import { log } from './logger.js'; -import { ApifyMcpServer } from './server.js'; -import { getActorDiscoveryTools, getActorAutoLoadingTools } from './tools.js'; - -log.setLevel(log.LEVELS.ERROR); - -const argv = parser(process.argv.slice(2), { - boolean: [ - 'enable-adding-actors', - 'enableActorAutoLoading', // deprecated - ], - string: ['actors'], - default: { - 'enable-adding-actors': false, - }, -}); - -const argEnableAddingActors = argv['enable-adding-actors'] || argv.enableActorAutoLoading || false; -const argActors = argv.actors?.split(',').map((actor: string) => actor.trim()) || []; - -if (!process.env.APIFY_TOKEN) { - log.error('APIFY_TOKEN is required but not set in the environment variables.'); - process.exit(1); -} - -async function main() { - const server = new ApifyMcpServer(); - await (argActors.length !== 0 - ? server.addToolsFromActors(argActors) - : server.addToolsFromDefaultActors()); - server.updateTools(getActorDiscoveryTools()); - if (argEnableAddingActors) { - server.updateTools(getActorAutoLoadingTools()); - } - const transport = new StdioServerTransport(); - await server.connect(transport); -} - -main().catch((error) => { - console.error('Server error:', error); // eslint-disable-line no-console - process.exit(1); -}); +export { ActorsMcpServer }; diff --git a/src/input.ts b/src/input.ts index 71f0c074..88a894e5 100644 --- a/src/input.ts +++ b/src/input.ts @@ -1,4 +1,8 @@ -import { log } from './logger.js'; +/* + * Actor input processing. + */ +import log from '@apify/log'; + import type { Input } from './types.js'; /** @@ -6,7 +10,7 @@ import type { Input } from './types.js'; * @param originalInput * @returns input */ -export async function processInput(originalInput: Partial): Promise { +export function processInput(originalInput: Partial): Input { const input = originalInput as Input; // actors can be a string or an array of strings @@ -15,14 +19,15 @@ export async function processInput(originalInput: Partial): Promise { - if (req.headers && req.get(HEADER_READINESS_PROBE) !== undefined) { - log.debug('Received readiness probe'); - res.status(200).json({ message: 'Server is ready' }).end(); - return; - } - try { - log.info(`Received GET message at: ${Routes.ROOT}`); - await processParamsAndUpdateTools(req.url); - res.status(200).json({ message: `Actor is using Model Context Protocol. ${HELP_MESSAGE}`, data: actorRun }).end(); - } catch (error) { - log.error(`Error in GET ${Routes.ROOT} ${error}`); - res.status(500).json({ message: 'Internal Server Error' }).end(); - } - }) - .head((_req: Request, res: Response) => { - res.status(200).end(); - }); - -app.route(Routes.SSE) - .get(async (req: Request, res: Response) => { - try { - log.info(`Received GET message at: ${Routes.SSE}`); - await processParamsAndUpdateTools(req.url); - transport = new SSEServerTransport(Routes.MESSAGE, res); - await mcpServer.connect(transport); - } catch (error) { - log.error(`Error in GET ${Routes.SSE}: ${error}`); - res.status(500).json({ message: 'Internal Server Error' }).end(); - } - }); - -app.route(Routes.MESSAGE) - .post(async (req: Request, res: Response) => { - try { - log.info(`Received POST message at: ${Routes.MESSAGE}`); - if (transport) { - await transport.handlePostMessage(req, res); - } else { - res.status(400).json({ - message: 'Server is not connected to the client. ' - + 'Connect to the server with GET request to /sse endpoint', - }); - } - } catch (error) { - log.error(`Error in POST ${Routes.MESSAGE}: ${error}`); - res.status(500).json({ message: 'Internal Server Error' }).end(); - } - }); - -// Catch-all for undefined routes -app.use((req: Request, res: Response) => { - res.status(404).json({ message: `There is nothing at route ${req.method} ${req.originalUrl}. ${HELP_MESSAGE}` }).end(); -}); +const mcpServer = new ActorsMcpServer(); -const input = await processInput((await Actor.getInput>()) ?? ({} as Input)); +const input = processInput((await Actor.getInput>()) ?? ({} as Input)); log.info(`Loaded input: ${JSON.stringify(input)} `); if (STANDBY_MODE) { + const app = createExpressApp(HOST, mcpServer); log.info('Actor is running in the STANDBY mode.'); - mcpServer.updateTools(getActorDiscoveryTools()); + // Do not load default Actors here, for mastra.ai template we need to start without default Actors + const tools = [searchTool, actorDefinitionTool]; if (input.enableAddingActors) { - mcpServer.updateTools(getActorAutoLoadingTools()); + tools.push(addTool, removeTool); } - const actors = input.actors ?? defaults.actors; - const actorsToLoad = Array.isArray(actors) ? actors : actors.split(','); - const actorTools = await getActorsAsTools(actorsToLoad); - mcpServer.updateTools(actorTools); + mcpServer.updateTools(tools); app.listen(PORT, () => { log.info(`The Actor web server is listening for user requests at ${HOST}`); }); @@ -156,9 +47,12 @@ if (STANDBY_MODE) { log.info('Actor is not designed to run in the NORMAL model (use this mode only for debugging purposes)'); if (input && !input.debugActor && !input.debugActorInput) { - await Actor.fail('If you need to debug a specific actor, please provide the debugActor and debugActorInput fields in the input'); + await Actor.fail('If you need to debug a specific Actor, please provide the debugActor and debugActorInput fields in the input'); } const options = { memory: input.maxActorMemoryBytes } as ActorCallOptions; - await mcpServer.callActorGetDataset(input.debugActor!, input.debugActorInput!, options); + const items = await callActorGetDataset(input.debugActor!, input.debugActorInput!, process.env.APIFY_TOKEN, options); + + await Actor.pushData(items); + log.info(`Pushed ${items.length} items to the dataset`); await Actor.exit(); } diff --git a/src/mcp/actors.ts b/src/mcp/actors.ts new file mode 100644 index 00000000..b5a45044 --- /dev/null +++ b/src/mcp/actors.ts @@ -0,0 +1,88 @@ +import type { ActorDefinition } from 'apify-client'; + +import { ApifyClient, getApifyAPIBaseUrl } from '../apify-client.js'; + +export async function isActorMCPServer(actorID: string, apifyToken: string): Promise { + const mcpPath = await getActorsMCPServerPath(actorID, apifyToken); + return (mcpPath?.length || 0) > 0; +} + +export async function getActorsMCPServerPath(actorID: string, apifyToken: string): Promise { + const actorDefinition = await getActorDefinition(actorID, apifyToken); + + if ('webServerMcpPath' in actorDefinition && typeof actorDefinition.webServerMcpPath === 'string') { + return actorDefinition.webServerMcpPath; + } + + return undefined; +} + +export async function getActorsMCPServerURL(actorID: string, apifyToken: string): Promise { + // TODO: get from API instead + const standbyBaseUrl = process.env.HOSTNAME === 'mcp-securitybyobscurity.apify.com' + ? 'securitybyobscurity.apify.actor' : 'apify.actor'; + const standbyUrl = await getActorStandbyURL(actorID, apifyToken, standbyBaseUrl); + const mcpPath = await getActorsMCPServerPath(actorID, apifyToken); + return `${standbyUrl}${mcpPath}`; +} + +/** +* Gets Actor ID from the Actor object. +* +* @param actorID +* @param apifyToken +*/ +export async function getRealActorID(actorID: string, apifyToken: string): Promise { + const apifyClient = new ApifyClient({ token: apifyToken }); + + const actor = apifyClient.actor(actorID); + const info = await actor.get(); + if (!info) { + throw new Error(`Actor ${actorID} not found`); + } + return info.id; +} + +/** +* Returns standby URL for given Actor ID. +* +* @param actorID +* @param standbyBaseUrl +* @param apifyToken +* @returns +*/ +export async function getActorStandbyURL(actorID: string, apifyToken: string, standbyBaseUrl = 'apify.actor'): Promise { + const actorRealID = await getRealActorID(actorID, apifyToken); + return `https://${actorRealID}.${standbyBaseUrl}`; +} + +export async function getActorDefinition(actorID: string, apifyToken: string): Promise { + const apifyClient = new ApifyClient({ token: apifyToken }); + const actor = apifyClient.actor(actorID); + const info = await actor.get(); + if (!info) { + throw new Error(`Actor ${actorID} not found`); + } + + const actorObjID = info.id; + const res = await fetch(`${getApifyAPIBaseUrl()}/v2/acts/${actorObjID}/builds/default`, { + headers: { + // This is done so tests can pass with public Actors without token + ...(apifyToken ? { Authorization: `Bearer ${apifyToken}` } : {}), + }, + }); + if (!res.ok) { + throw new Error(`Failed to fetch default build for actor ${actorID}: ${res.statusText}`); + } + const json = await res.json() as any; // eslint-disable-line @typescript-eslint/no-explicit-any + const buildInfo = json.data; + if (!buildInfo) { + throw new Error(`Default build for Actor ${actorID} not found`); + } + const { actorDefinition } = buildInfo; + if (!actorDefinition) { + throw new Error(`Actor default build ${actorID} does not have Actor definition`); + } + + return actorDefinition; +} diff --git a/src/mcp/client.ts b/src/mcp/client.ts new file mode 100644 index 00000000..2f5537c1 --- /dev/null +++ b/src/mcp/client.ts @@ -0,0 +1,41 @@ +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; + +import { getMCPServerID } from './utils.js'; + +/** + * Creates and connects a ModelContextProtocol client. + */ +export async function createMCPClient( + url: string, token: string, +): Promise { + const transport = new SSEClientTransport( + new URL(url), + { + requestInit: { + headers: { + authorization: `Bearer ${token}`, + }, + }, + eventSourceInit: { + // The EventSource package augments EventSourceInit with a "fetch" parameter. + // You can use this to set additional headers on the outgoing request. + // Based on this example: https://github.com/modelcontextprotocol/typescript-sdk/issues/118 + async fetch(input: Request | URL | string, init?: RequestInit) { + const headers = new Headers(init?.headers || {}); + headers.set('authorization', `Bearer ${token}`); + return fetch(input, { ...init, headers }); + }, + // We have to cast to "any" to use it, since it's non-standard + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }); + + const client = new Client({ + name: getMCPServerID(url), + version: '1.0.0', + }); + + await client.connect(transport); + + return client; +} diff --git a/src/mcp/const.ts b/src/mcp/const.ts new file mode 100644 index 00000000..a3cba339 --- /dev/null +++ b/src/mcp/const.ts @@ -0,0 +1,2 @@ +export const MAX_TOOL_NAME_LENGTH = 64; +export const SERVER_ID_LENGTH = 8; diff --git a/src/mcp/proxy.ts b/src/mcp/proxy.ts new file mode 100644 index 00000000..b3f7c410 --- /dev/null +++ b/src/mcp/proxy.ts @@ -0,0 +1,41 @@ +import type { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import Ajv from 'ajv'; + +import type { ActorMCPTool, ToolWrap } from '../types.js'; +import { getMCPServerID, getProxyMCPServerToolName } from './utils.js'; + +export async function getMCPServerTools( + actorID: string, + client: Client, + // Name of the MCP server + serverUrl: string, +): Promise { + const res = await client.listTools(); + const { tools } = res; + + const ajv = new Ajv({ coerceTypes: 'array', strict: false }); + + const compiledTools: ToolWrap[] = []; + for (const tool of tools) { + const mcpTool: ActorMCPTool = { + actorID, + serverId: getMCPServerID(serverUrl), + serverUrl, + originToolName: tool.name, + + name: getProxyMCPServerToolName(serverUrl, tool.name), + description: tool.description || '', + inputSchema: tool.inputSchema, + ajvValidate: ajv.compile(tool.inputSchema), + }; + + const wrap: ToolWrap = { + type: 'actor-mcp', + tool: mcpTool, + }; + + compiledTools.push(wrap); + } + + return compiledTools; +} diff --git a/src/mcp/server.ts b/src/mcp/server.ts new file mode 100644 index 00000000..2973402e --- /dev/null +++ b/src/mcp/server.ts @@ -0,0 +1,210 @@ +/** + * Model Context Protocol (MCP) server for Apify Actors + */ + +import type { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; +import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; +import type { ActorCallOptions } from 'apify-client'; + +import log from '@apify/log'; + +import { + ACTOR_OUTPUT_MAX_CHARS_PER_ITEM, + ACTOR_OUTPUT_TRUNCATED_MESSAGE, + defaults, + SERVER_NAME, + SERVER_VERSION, +} from '../const.js'; +import { actorDefinitionTool, callActorGetDataset, getActorsAsTools, searchTool } from '../tools/index.js'; +import { actorNameToToolName } from '../tools/utils.js'; +import type { ActorMCPTool, ActorTool, HelperTool, ToolWrap } from '../types.js'; +import { createMCPClient } from './client.js'; +import { processParamsGetTools } from './utils.js'; + +/** + * Create Apify MCP server + */ +export class ActorsMcpServer { + public readonly server: Server; + public readonly tools: Map; + + constructor() { + this.server = new Server( + { + name: SERVER_NAME, + version: SERVER_VERSION, + }, + { + capabilities: { + tools: { listChanged: true }, + logging: {}, + }, + }, + ); + this.tools = new Map(); + this.setupErrorHandling(); + this.setupToolHandlers(); + + // Add default tools + this.updateTools([searchTool, actorDefinitionTool]); + } + + /** + * Loads missing default tools. + */ + public async loadDefaultTools(apifyToken: string) { + const missingDefaultTools = defaults.actors.filter((name) => !this.tools.has(actorNameToToolName(name))); + const tools = await getActorsAsTools(missingDefaultTools, apifyToken); + if (tools.length > 0) this.updateTools(tools); + } + + /** + * Loads tools from URL params. + * + * This method also handles enabling of Actor auto loading via the processParamsGetTools. + * + * Used primarily for SSE. + */ + public async loadToolsFromUrl(url: string, apifyToken: string) { + const tools = await processParamsGetTools(url, apifyToken); + if (tools.length > 0) this.updateTools(tools); + } + + /** + * Upsert new tools. + * @param tools - Array of tool wrappers. + * @returns Array of tool wrappers. + */ + public updateTools(tools: ToolWrap[]) { + for (const wrap of tools) { + this.tools.set(wrap.tool.name, wrap); + log.info(`Added/updated tool: ${wrap.tool.name}`); + } + return tools; + } + + /** + * Returns an array of tool names. + * @returns {string[]} - An array of tool names. + */ + public getToolNames(): string[] { + return Array.from(this.tools.keys()); + } + + private setupErrorHandling(): void { + this.server.onerror = (error) => { + console.error('[MCP Error]', error); // eslint-disable-line no-console + }; + process.on('SIGINT', async () => { + await this.server.close(); + process.exit(0); + }); + } + + private setupToolHandlers(): void { + /** + * Handles the request to list tools. + * @param {object} request - The request object. + * @returns {object} - The response object containing the tools. + */ + this.server.setRequestHandler(ListToolsRequestSchema, async () => { + // TODO if there is actor-mcp as a tool, also list the tools from that Actor + const tools = Array.from(this.tools.values()).map((tool) => (tool.tool)); + return { tools }; + }); + + /** + * Handles the request to call a tool. + * @param {object} request - The request object containing tool name and arguments. + * @throws {Error} - Throws an error if the tool is unknown or arguments are invalid. + */ + this.server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + const apifyToken = (request.params.apifyToken || process.env.APIFY_TOKEN) as string; + + // Remove apifyToken from request.params just in case + delete request.params.apifyToken; + + // Validate token + if (!apifyToken) { + throw new Error('APIFY_TOKEN is required but not set in the environment variables or passed as a parameter.'); + } + + // Find tool by name or actor full name + const tool = Array.from(this.tools.values()) + .find((t) => t.tool.name === name || (t.type === 'actor' && (t.tool as ActorTool).actorFullName === name)); + if (!tool) { + // TODO: handle errors better, server.sendLoggingMessage ( ) + throw new Error(`Unknown tool: ${name}`); + } + if (!args) { + throw new Error(`Missing arguments for tool: ${name}`); + } + log.info(`Validate arguments for tool: ${tool.tool.name} with arguments: ${JSON.stringify(args)}`); + if (!tool.tool.ajvValidate(args)) { + throw new Error(`Invalid arguments for tool ${tool.tool.name}: args: ${JSON.stringify(args)} error: ${JSON.stringify(tool?.tool.ajvValidate.errors)}`); + } + + try { + // Handle internal tool + if (tool.type === 'internal') { + const internalTool = tool.tool as HelperTool; + const res = await internalTool.call({ + args, + apifyMcpServer: this, + mcpServer: this.server, + apifyToken, + }) as object; + + return { ...res }; + } + + if (tool.type === 'actor-mcp') { + const serverTool = tool.tool as ActorMCPTool; + let client: Client | undefined; + try { + client = await createMCPClient(serverTool.serverUrl, apifyToken); + const res = await client.callTool({ + name: serverTool.originToolName, + arguments: args, + }); + + return { ...res }; + } finally { + if (client) await client.close(); + } + } + + // Handle actor tool + if (tool.type === 'actor') { + const actorTool = tool.tool as ActorTool; + + const callOptions: ActorCallOptions = { + memory: actorTool.memoryMbytes, + }; + + const items = await callActorGetDataset(actorTool.actorFullName, args, apifyToken as string, callOptions); + + const content = items.map((item) => { + const text = JSON.stringify(item).slice(0, ACTOR_OUTPUT_MAX_CHARS_PER_ITEM); + return text.length === ACTOR_OUTPUT_MAX_CHARS_PER_ITEM + ? { type: 'text', text: `${text} ... ${ACTOR_OUTPUT_TRUNCATED_MESSAGE}` } + : { type: 'text', text }; + }); + return { content }; + } + } catch (error) { + log.error(`Error calling tool: ${error}`); + throw new Error(`Error calling tool: ${error}`); + } + + throw new Error(`Tool ${name} is not implemented`); + }); + } + + async connect(transport: Transport): Promise { + await this.server.connect(transport); + } +} diff --git a/src/mcp/utils.ts b/src/mcp/utils.ts new file mode 100644 index 00000000..e7b8b3d7 --- /dev/null +++ b/src/mcp/utils.ts @@ -0,0 +1,60 @@ +import { createHash } from 'node:crypto'; +import { parse } from 'node:querystring'; + +import { processInput } from '../input.js'; +import { addTool, getActorsAsTools, removeTool } from '../tools/index.js'; +import type { Input, ToolWrap } from '../types.js'; +import { MAX_TOOL_NAME_LENGTH, SERVER_ID_LENGTH } from './const.js'; + +/** + * Generates a unique server ID based on the provided URL. + * + * URL is used instead of Actor ID becase one Actor may expose multiple servers - legacy SSE / streamable HTTP. + * + * @param url The URL to generate the server ID from. + * @returns A unique server ID. + */ +export function getMCPServerID(url: string): string { + const serverHashDigest = createHash('sha256').update(url).digest('hex'); + + return serverHashDigest.slice(0, SERVER_ID_LENGTH); +} + +/** + * Generates a unique tool name based on the provided URL and tool name. + * @param url The URL to generate the tool name from. + * @param toolName The tool name to generate the tool name from. + * @returns A unique tool name. + */ +export function getProxyMCPServerToolName(url: string, toolName: string): string { + const prefix = getMCPServerID(url); + + const fullName = `${prefix}-${toolName}`; + return fullName.slice(0, MAX_TOOL_NAME_LENGTH); +} + +/** + * Process input parameters and get tools + * If URL contains query parameter `actors`, return tools from Actors otherwise return null. + * @param url + * @param apifyToken + */ +export async function processParamsGetTools(url: string, apifyToken: string) { + const input = parseInputParamsFromUrl(url); + let tools: ToolWrap[] = []; + if (input.actors) { + const actors = input.actors as string[]; + // Normal Actors as a tool + tools = await getActorsAsTools(actors, apifyToken); + } + if (input.enableAddingActors) { + tools.push(addTool, removeTool); + } + return tools; +} + +export function parseInputParamsFromUrl(url: string): Input { + const query = url.split('?')[1] || ''; + const params = parse(query) as unknown as Input; + return processInput(params); +} diff --git a/src/server.ts b/src/server.ts deleted file mode 100644 index 46d865d6..00000000 --- a/src/server.ts +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env node -/** - * Model Context Protocol (MCP) server for Apify Actors - */ -import { Server } from '@modelcontextprotocol/sdk/server/index.js'; -import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; -import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; -import type { ApifyClientOptions } from 'apify'; -import { Actor } from 'apify'; -import type { ActorCallOptions } from 'apify-client'; -import { ApifyClient } from 'apify-client'; -import type { AxiosRequestConfig } from 'axios'; - -import { - filterSchemaProperties, - getActorDefinition, - getActorsAsTools, - shortenProperties, -} from './actors.js'; -import { - ACTOR_OUTPUT_MAX_CHARS_PER_ITEM, - ACTOR_OUTPUT_TRUNCATED_MESSAGE, - defaults, - InternalTools, - SERVER_NAME, - SERVER_VERSION, - USER_AGENT_ORIGIN, -} from './const.js'; -import { log } from './logger.js'; -import { - RemoveActorToolArgsSchema, - AddActorToToolsArgsSchema, - DiscoverActorsArgsSchema, - searchActorsByKeywords, - GetActorDefinition, -} from './tools.js'; -import type { ISchemaProperties, Tool } from './types.js'; - -/** - * Create Apify MCP server - */ -export class ApifyMcpServer { - private server: Server; - private tools: Map; - - constructor() { - this.server = new Server( - { - name: SERVER_NAME, - version: SERVER_VERSION, - }, - { - capabilities: { - tools: { listChanged: true }, - }, - }, - ); - this.tools = new Map(); - this.setupErrorHandling(); - this.setupToolHandlers(); - } - - /** - * Adds a User-Agent header to the request config. - * @param config - * @private - */ - private addUserAgent(config: AxiosRequestConfig): AxiosRequestConfig { - const updatedConfig = { ...config }; - updatedConfig.headers = updatedConfig.headers ?? {}; - updatedConfig.headers['User-Agent'] = `${updatedConfig.headers['User-Agent'] ?? ''}; ${USER_AGENT_ORIGIN}`; - return updatedConfig; - } - - /** - * Calls an Apify actor and retrieves the dataset items. - * - * It requires the `APIFY_TOKEN` environment variable to be set. - * If the `APIFY_IS_AT_HOME` the dataset items are pushed to the Apify dataset. - * - * @param {string} actorName - The name of the actor to call. - * @param {ActorCallOptions} callOptions - The options to pass to the actor. - * @param {unknown} input - The input to pass to the actor. - * @returns {Promise} - A promise that resolves to an array of dataset items. - * @throws {Error} - Throws an error if the `APIFY_TOKEN` is not set - */ - public async callActorGetDataset( - actorName: string, - input: unknown, - callOptions: ActorCallOptions | undefined = undefined, - ): Promise { - const name = actorName; - try { - log.info(`Calling actor ${name} with input: ${JSON.stringify(input)}`); - - const options: ApifyClientOptions = { requestInterceptors: [this.addUserAgent] }; - const client = new ApifyClient({ ...options, token: process.env.APIFY_TOKEN }); - const actorClient = client.actor(name); - - const results = await actorClient.call(input, callOptions); - const dataset = await client.dataset(results.defaultDatasetId).listItems(); - log.info(`Actor ${name} finished with ${dataset.items.length} items`); - - if (process.env.APIFY_IS_AT_HOME) { - await Actor.pushData(dataset.items); - log.info(`Pushed ${dataset.items.length} items to the dataset`); - } - return dataset.items; - } catch (error) { - log.error(`Error calling actor: ${error}. Actor: ${name}, input: ${JSON.stringify(input)}`); - throw new Error(`Error calling actor: ${error}`); - } - } - - public async addToolsFromActors(actors: string[]) { - const tools = await getActorsAsTools(actors); - this.updateTools(tools); - return tools; - } - - public async addToolsFromDefaultActors() { - await this.addToolsFromActors(defaults.actors); - } - - public updateTools(tools: Tool[]): void { - for (const tool of tools) { - this.tools.set(tool.name, tool); - log.info(`Added/Updated tool: ${tool.actorFullName} (tool: ${tool.name})`); - } - } - - /** - * Returns an array of tool names. - * @returns {string[]} - An array of tool names. - */ - public getToolNames(): string[] { - return Array.from(this.tools.keys()); - } - - private setupErrorHandling(): void { - this.server.onerror = (error) => { - console.error('[MCP Error]', error); // eslint-disable-line no-console - }; - process.on('SIGINT', async () => { - await this.server.close(); - process.exit(0); - }); - } - - private setupToolHandlers(): void { - this.server.setRequestHandler(ListToolsRequestSchema, async () => { - return { tools: Array.from(this.tools.values()) }; - }); - - /** - * Handles the request to call a tool. - * @param {object} request - The request object containing tool name and arguments. - * @throws {Error} - Throws an error if the tool is unknown or arguments are invalid. - */ - this.server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - - const tool = Array.from(this.tools.values()).find((t) => t.name === name || t.actorFullName === name); - if (!tool) { - throw new Error(`Unknown tool: ${name}`); - } - if (!args) { - throw new Error(`Missing arguments for tool: ${name}`); - } - log.info(`Validate arguments for tool: ${tool.name} with arguments: ${JSON.stringify(args)}`); - if (!tool.ajvValidate(args)) { - throw new Error(`Invalid arguments for tool ${tool.name}: args: ${JSON.stringify(args)} error: ${JSON.stringify(tool?.ajvValidate.errors)}`); - } - - try { - switch (name) { - case InternalTools.ADD_ACTOR_TO_TOOLS: { - const parsed = AddActorToToolsArgsSchema.parse(args); - const toolsAdded = await this.addToolsFromActors([parsed.actorName]); - await this.server.notification({ method: 'notifications/tools/list_changed' }); - return { content: [{ type: 'text', text: `Actor added: ${toolsAdded.map((t) => `${t.actorFullName} (tool name: ${t.name})`).join(', ')}` }] }; - } - case InternalTools.REMOVE_ACTOR_FROM_TOOLS: { - const parsed = RemoveActorToolArgsSchema.parse(args); - this.tools.delete(parsed.toolName); - await this.server.notification({ method: 'notifications/tools/list_changed' }); - return { content: [{ type: 'text', text: `Tool ${parsed.toolName} was removed` }] }; - } - case InternalTools.DISCOVER_ACTORS: { - const parsed = DiscoverActorsArgsSchema.parse(args); - const actors = await searchActorsByKeywords( - parsed.search, - parsed.limit, - parsed.offset, - ); - return { content: actors?.map((item) => ({ type: 'text', text: JSON.stringify(item) })) }; - } - case InternalTools.GET_ACTOR_DETAILS: { - const parsed = GetActorDefinition.parse(args); - const v = await getActorDefinition(parsed.actorName, parsed.limit); - if (v && v.input && 'properties' in v.input && v.input) { - const properties = filterSchemaProperties(v.input.properties as { [key: string]: ISchemaProperties }); - v.input.properties = shortenProperties(properties); - } - return { content: [{ type: 'text', text: JSON.stringify(v) }] }; - } - default: { - const items = await this.callActorGetDataset(tool.actorFullName, args, { memory: tool.memoryMbytes } as ActorCallOptions); - const content = items.map((item) => { - const text = JSON.stringify(item).slice(0, ACTOR_OUTPUT_MAX_CHARS_PER_ITEM); - return text.length === ACTOR_OUTPUT_MAX_CHARS_PER_ITEM - ? { type: 'text', text: `${text} ... ${ACTOR_OUTPUT_TRUNCATED_MESSAGE}` } - : { type: 'text', text }; - }); - return { content }; - } - } - } catch (error) { - log.error(`Error calling tool: ${error}`); - throw new Error(`Error calling tool: ${error}`); - } - }); - } - - async connect(transport: Transport): Promise { - await this.server.connect(transport); - } -} diff --git a/src/stdio.ts b/src/stdio.ts new file mode 100644 index 00000000..587a919a --- /dev/null +++ b/src/stdio.ts @@ -0,0 +1,65 @@ +#!/usr/bin/env node +/** + * This script initializes and starts the Apify MCP server using the Stdio transport. + * + * Usage: + * node --actors= + * + * Command-line arguments: + * --actors - A comma-separated list of Actor full names to add to the server. + * + * Example: + * node stdio.js --actors=apify/google-search-scraper,apify/instagram-scraper + */ + +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import minimist from 'minimist'; + +import log from '@apify/log'; + +import { defaults } from './const.js'; +import { ActorsMcpServer } from './mcp/server.js'; +import { addTool, getActorsAsTools, removeTool } from './tools/index.js'; + +// Configure logging, set to ERROR +log.setLevel(log.LEVELS.ERROR); + +// Parse command line arguments +const parser = minimist; +const argv = parser(process.argv.slice(2), { + boolean: [ + 'enable-adding-actors', + 'enableActorAutoLoading', // deprecated + ], + string: ['actors'], + default: { + 'enable-adding-actors': false, + }, +}); +const { actors = '', enableActorAutoLoading = false } = argv; +const actorList = actors ? actors.split(',').map((a: string) => a.trim()) : []; + +// Validate environment +if (!process.env.APIFY_TOKEN) { + log.error('APIFY_TOKEN is required but not set in the environment variables.'); + process.exit(1); +} + +async function main() { + const mcpServer = new ActorsMcpServer(); + // Initialize tools + const tools = await getActorsAsTools(actorList.length ? actorList : defaults.actors, process.env.APIFY_TOKEN as string); + if (enableActorAutoLoading) { + tools.push(addTool, removeTool); + } + mcpServer.updateTools(tools); + + // Start server + const transport = new StdioServerTransport(); + await mcpServer.connect(transport); +} + +main().catch((error) => { + log.error('Server error:', error); + process.exit(1); +}); diff --git a/src/tools.ts b/src/tools.ts deleted file mode 100644 index 76c581b5..00000000 --- a/src/tools.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Ajv } from 'ajv'; -import type { ActorStoreList } from 'apify-client'; -import { ApifyClient } from 'apify-client'; -import { z } from 'zod'; -import { zodToJsonSchema } from 'zod-to-json-schema'; - -import { actorNameToToolName } from './actors.js'; -import { ACTOR_README_MAX_LENGTH, InternalTools } from './const.js'; -import type { ActorStorePruned, PricingInfo, Tool } from './types.js'; - -export const DiscoverActorsArgsSchema = z.object({ - limit: z.number() - .int() - .min(1) - .max(100) - .default(10) - .describe('The maximum number of Actors to return. Default value is 10.'), - offset: z.number() - .int() - .min(0) - .default(0) - .describe('The number of elements that should be skipped at the start. Default value is 0.'), - search: z.string() - .default('') - .describe('String of key words to search by. ' - + 'Searches the title, name, description, username, and readme of an Actor.' - + 'Only key word search is supported, no advanced search.' - + 'Always prefer simple keywords over complex queries.'), - category: z.string() - .default('') - .describe('Filters the results by the specified category.'), -}); - -export const RemoveActorToolArgsSchema = z.object({ - toolName: z.string() - .describe('Tool name to remove from available tools.') - .transform((val) => actorNameToToolName(val)), -}); - -export const AddActorToToolsArgsSchema = z.object({ - actorName: z.string() - .describe('Add an Actor to available tools by Actor ID or Actor full name.' - + 'Actor name is always composed from `username/name`'), -}); - -export const GetActorDefinition = z.object({ - actorName: z.string() - .describe('Retrieve input, readme, and other details for Actor ID or Actor full name. ' - + 'Actor name is always composed from `username/name`'), - limit: z.number() - .int() - .default(ACTOR_README_MAX_LENGTH) - .describe(`Truncate the README to this limit. Default value is ${ACTOR_README_MAX_LENGTH}.`), -}); - -export function getActorAutoLoadingTools(): Tool[] { - const ajv = new Ajv({ coerceTypes: 'array', strict: false }); - return [ - { - name: InternalTools.ADD_ACTOR_TO_TOOLS, - actorFullName: InternalTools.ADD_ACTOR_TO_TOOLS, - description: 'Add an Actor to available tools by Actor ID or Actor name. ' - + 'Do not execute the Actor, only add it and list it in available tools. ' - + 'Never run the tool without user consent! ' - + 'For example, add a tool with username/name when user wants to scrape data from a website.', - inputSchema: zodToJsonSchema(AddActorToToolsArgsSchema), - ajvValidate: ajv.compile(zodToJsonSchema(AddActorToToolsArgsSchema)), - }, - { - name: InternalTools.REMOVE_ACTOR_FROM_TOOLS, - actorFullName: InternalTools.REMOVE_ACTOR_FROM_TOOLS, - description: 'Remove tool by name from available tools. ' - + 'For example, when user says, I do not need a tool username/name anymore', - inputSchema: zodToJsonSchema(RemoveActorToolArgsSchema), - ajvValidate: ajv.compile(zodToJsonSchema(RemoveActorToolArgsSchema)), - }, - ]; -} - -export function getActorDiscoveryTools(): Tool[] { - const ajv = new Ajv({ coerceTypes: 'array', strict: false }); - return [ - { - name: InternalTools.DISCOVER_ACTORS, - actorFullName: InternalTools.DISCOVER_ACTORS, - description: `Discover available Actors using full text search using keywords.` - + `Users try to discover Actors using free form query in this case search query needs to be converted to full text search. ` - + `Prefer Actors from Apify as they are generally more reliable and have better support. ` - + `Returns a list of Actors with name, description, run statistics, pricing, starts, and URL. ` - + `You perhaps need to use this tool several times to find the right Actor. ` - + `Limit number of results returned but ensure that relevant results are returned. `, - inputSchema: zodToJsonSchema(DiscoverActorsArgsSchema), - ajvValidate: ajv.compile(zodToJsonSchema(DiscoverActorsArgsSchema)), - }, - { - name: InternalTools.GET_ACTOR_DETAILS, - actorFullName: InternalTools.GET_ACTOR_DETAILS, - description: 'Get documentation, readme, input schema and other details about an Actor. ' - + 'For example, when user says, I need to know more about web crawler Actor.' - + 'Get details for an Actor with with Actor ID or Actor full name, i.e. username/name.' - + `Limit the length of the README if needed.`, - inputSchema: zodToJsonSchema(GetActorDefinition), - ajvValidate: ajv.compile(zodToJsonSchema(GetActorDefinition)), - }, - ]; -} - -function pruneActorStoreInfo(response: ActorStoreList): ActorStorePruned { - const stats = response.stats || {}; - const pricingInfo = (response.currentPricingInfo || {}) as PricingInfo; - return { - id: response.id, - name: response.name?.toString() || '', - username: response.username?.toString() || '', - actorFullName: `${response.username}/${response.name}`, - title: response.title?.toString() || '', - description: response.description?.toString() || '', - stats: { - totalRuns: stats.totalRuns, - totalUsers30Days: stats.totalUsers30Days, - publicActorRunStats30Days: 'publicActorRunStats30Days' in stats - ? stats.publicActorRunStats30Days : {}, - }, - currentPricingInfo: { - pricingModel: pricingInfo.pricingModel?.toString() || '', - pricePerUnitUsd: pricingInfo?.pricePerUnitUsd ?? 0, - trialMinutes: pricingInfo?.trialMinutes ?? 0, - }, - url: response.url?.toString() || '', - totalStars: 'totalStars' in response ? (response.totalStars as number) : null, - }; -} - -export async function searchActorsByKeywords( - search: string, - limit: number | undefined = undefined, - offset: number | undefined = undefined, -): Promise { - const client = new ApifyClient({ token: process.env.APIFY_TOKEN }); - const results = await client.store().list({ search, limit, offset }); - return results.items.map((x) => pruneActorStoreInfo(x)); -} diff --git a/src/tools/actor.ts b/src/tools/actor.ts new file mode 100644 index 00000000..2c4e7744 --- /dev/null +++ b/src/tools/actor.ts @@ -0,0 +1,170 @@ +import type { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { Ajv } from 'ajv'; +import type { ActorCallOptions } from 'apify-client'; + +import log from '@apify/log'; + +import { ApifyClient } from '../apify-client.js'; +import { ACTOR_ADDITIONAL_INSTRUCTIONS, ACTOR_MAX_MEMORY_MBYTES } from '../const.js'; +import { getActorsMCPServerURL, isActorMCPServer } from '../mcp/actors.js'; +import { createMCPClient } from '../mcp/client.js'; +import { getMCPServerTools } from '../mcp/proxy.js'; +import type { ToolWrap } from '../types.js'; +import { getActorDefinition } from './build.js'; +import { + actorNameToToolName, + addEnumsToDescriptionsWithExamples, + buildNestedProperties, + filterSchemaProperties, + markInputPropertiesAsRequired, + shortenProperties, +} from './utils.js'; + +/** + * Calls an Apify actor and retrieves the dataset items. + * + * + * It requires the `APIFY_TOKEN` environment variable to be set. + * If the `APIFY_IS_AT_HOME` the dataset items are pushed to the Apify dataset. + * + * @param {string} actorName - The name of the actor to call. + * @param {ActorCallOptions} callOptions - The options to pass to the actor. + * @param {unknown} input - The input to pass to the actor. + * @param {string} apifyToken - The Apify token to use for authentication. + * @returns {Promise} - A promise that resolves to an array of dataset items. + * @throws {Error} - Throws an error if the `APIFY_TOKEN` is not set + */ +export async function callActorGetDataset( + actorName: string, + input: unknown, + apifyToken: string, + callOptions: ActorCallOptions | undefined = undefined, +): Promise { + const name = actorName; + try { + log.info(`Calling Actor ${name} with input: ${JSON.stringify(input)}`); + + const client = new ApifyClient({ token: apifyToken }); + const actorClient = client.actor(name); + + const results = await actorClient.call(input, callOptions); + const dataset = await client.dataset(results.defaultDatasetId).listItems(); + log.info(`Actor ${name} finished with ${dataset.items.length} items`); + + return dataset.items; + } catch (error) { + log.error(`Error calling actor: ${error}. Actor: ${name}, input: ${JSON.stringify(input)}`); + throw new Error(`Error calling Actor: ${error}`); + } +} + +/** + * This function is used to fetch normal non-MCP server Actors as a tool. + * + * Fetches actor input schemas by Actor IDs or Actor full names and creates MCP tools. + * + * This function retrieves the input schemas for the specified actors and compiles them into MCP tools. + * It uses the AJV library to validate the input schemas. + * + * Tool name can't contain /, so it is replaced with _ + * + * The input schema processing workflow: + * 1. Properties are marked as required using markInputPropertiesAsRequired() to add "REQUIRED" prefix to descriptions + * 2. Nested properties are built by analyzing editor type (proxy, requestListSources) using buildNestedProperties() + * 3. Properties are filtered using filterSchemaProperties() + * 4. Properties are shortened using shortenProperties() + * 5. Enums are added to descriptions with examples using addEnumsToDescriptionsWithExamples() + * + * @param {string[]} actors - An array of actor IDs or Actor full names. + * @returns {Promise} - A promise that resolves to an array of MCP tools. + */ +export async function getNormalActorsAsTools( + actors: string[], + apifyToken: string, +): Promise { + const ajv = new Ajv({ coerceTypes: 'array', strict: false }); + const getActorDefinitionWithToken = async (actorId: string) => { + const actor = await getActorDefinition(actorId, apifyToken); + return actor; + }; + const results = await Promise.all(actors.map(getActorDefinitionWithToken)); + const tools: ToolWrap[] = []; + for (const result of results) { + if (result) { + if (result.input && 'properties' in result.input && result.input) { + result.input.properties = markInputPropertiesAsRequired(result.input); + result.input.properties = buildNestedProperties(result.input.properties); + result.input.properties = filterSchemaProperties(result.input.properties); + result.input.properties = shortenProperties(result.input.properties); + result.input.properties = addEnumsToDescriptionsWithExamples(result.input.properties); + } + try { + const memoryMbytes = result.defaultRunOptions?.memoryMbytes || ACTOR_MAX_MEMORY_MBYTES; + tools.push({ + type: 'actor', + tool: { + name: actorNameToToolName(result.actorFullName), + actorFullName: result.actorFullName, + description: `${result.description} Instructions: ${ACTOR_ADDITIONAL_INSTRUCTIONS}`, + inputSchema: result.input || {}, + ajvValidate: ajv.compile(result.input || {}), + memoryMbytes: memoryMbytes > ACTOR_MAX_MEMORY_MBYTES ? ACTOR_MAX_MEMORY_MBYTES : memoryMbytes, + }, + }); + } catch (validationError) { + log.error(`Failed to compile AJV schema for Actor: ${result.actorFullName}. Error: ${validationError}`); + } + } + } + return tools; +} + +async function getMCPServersAsTools( + actors: string[], + apifyToken: string, +): Promise { + const actorsMCPServerTools: ToolWrap[] = []; + for (const actorID of actors) { + const serverUrl = await getActorsMCPServerURL(actorID, apifyToken); + log.info(`ActorID: ${actorID} MCP server URL: ${serverUrl}`); + + let client: Client | undefined; + try { + client = await createMCPClient(serverUrl, apifyToken); + const serverTools = await getMCPServerTools(actorID, client, serverUrl); + actorsMCPServerTools.push(...serverTools); + } finally { + if (client) await client.close(); + } + } + + return actorsMCPServerTools; +} + +export async function getActorsAsTools( + actors: string[], + apifyToken: string, +): Promise { + log.debug(`Fetching actors as tools...`); + log.debug(`Actors: ${actors}`); + // Actorized MCP servers + const actorsMCPServers: string[] = []; + for (const actorID of actors) { + // TODO: rework, we are fetching actor definition from API twice - in the getMCPServerTools + if (await isActorMCPServer(actorID, apifyToken)) { + actorsMCPServers.push(actorID); + } + } + // Normal Actors as a tool + const toolActors = actors.filter((actorID) => !actorsMCPServers.includes(actorID)); + log.debug(`actorsMCPserver: ${actorsMCPServers}`); + log.debug(`toolActors: ${toolActors}`); + + // Normal Actors as a tool + const normalTools = await getNormalActorsAsTools(toolActors, apifyToken); + + // Tools from Actorized MCP servers + const mcpServerTools = await getMCPServersAsTools(actorsMCPServers, apifyToken); + + return [...normalTools, ...mcpServerTools]; +} diff --git a/src/tools/build.ts b/src/tools/build.ts new file mode 100644 index 00000000..35ae6483 --- /dev/null +++ b/src/tools/build.ts @@ -0,0 +1,139 @@ +import { Ajv } from 'ajv'; +import { z } from 'zod'; +import zodToJsonSchema from 'zod-to-json-schema'; + +import log from '@apify/log'; + +import { ApifyClient } from '../apify-client.js'; +import { ACTOR_README_MAX_LENGTH, HelperTools } from '../const.js'; +import type { + ActorDefinitionPruned, + ActorDefinitionWithDesc, + InternalTool, + ISchemaProperties, + ToolWrap, +} from '../types.js'; +import { filterSchemaProperties, shortenProperties } from './utils.js'; + +const ajv = new Ajv({ coerceTypes: 'array', strict: false }); + +/** + * Get Actor input schema by Actor name. + * First, fetch the Actor details to get the default build tag and buildId. + * Then, fetch the build details and return actorName, description, and input schema. + * @param {string} actorIdOrName - Actor ID or Actor full name. + * @param {number} limit - Truncate the README to this limit. + * @param {string} apifyToken + * @returns {Promise} - The actor definition with description or null if not found. + */ +export async function getActorDefinition( + actorIdOrName: string, + apifyToken: string, + limit: number = ACTOR_README_MAX_LENGTH, +): Promise { + const client = new ApifyClient({ token: apifyToken }); + const actorClient = client.actor(actorIdOrName); + try { + // Fetch actor details + const actor = await actorClient.get(); + if (!actor) { + log.error(`Failed to fetch input schema for Actor: ${actorIdOrName}. Actor not found.`); + return null; + } + + // fnesveda: The default build is not necessarily tagged, you can specify any build number as default build. + // There will be a new API endpoint to fetch a default build. + // For now, we'll use the tagged build, it will work for 90% of Actors. Later, we can update this. + const tag = actor.defaultRunOptions?.build || ''; + const buildId = actor.taggedBuilds?.[tag]?.buildId || ''; + + if (!buildId) { + log.error(`Failed to fetch input schema for Actor: ${actorIdOrName}. Build ID not found.`); + return null; + } + // Fetch build details and return the input schema + const buildDetails = await client.build(buildId).get(); + if (buildDetails?.actorDefinition) { + const actorDefinitions = buildDetails?.actorDefinition as ActorDefinitionWithDesc; + actorDefinitions.id = actor.id; + actorDefinitions.readme = truncateActorReadme(actorDefinitions.readme || '', limit); + actorDefinitions.description = actor.description || ''; + actorDefinitions.actorFullName = `${actor.username}/${actor.name}`; + actorDefinitions.defaultRunOptions = actor.defaultRunOptions; + return pruneActorDefinition(actorDefinitions); + } + return null; + } catch (error) { + const errorMessage = `Failed to fetch input schema for Actor: ${actorIdOrName} with error ${error}.`; + log.error(errorMessage); + throw new Error(errorMessage); + } +} +function pruneActorDefinition(response: ActorDefinitionWithDesc): ActorDefinitionPruned { + return { + id: response.id, + actorFullName: response.actorFullName || '', + buildTag: response?.buildTag || '', + readme: response?.readme || '', + input: response?.input && 'type' in response.input && 'properties' in response.input + ? { + ...response.input, + type: response.input.type as string, + properties: response.input.properties as Record, + } + : undefined, + description: response.description, + defaultRunOptions: response.defaultRunOptions, + }; +} +/** Prune Actor README if it is too long + * If the README is too long + * - We keep the README as it is up to the limit. + * - After the limit, we keep heading only + * - We add a note that the README was truncated because it was too long. + */ +function truncateActorReadme(readme: string, limit = ACTOR_README_MAX_LENGTH): string { + if (readme.length <= limit) { + return readme; + } + const readmeFirst = readme.slice(0, limit); + const readmeRest = readme.slice(limit); + const lines = readmeRest.split('\n'); + const prunedReadme = lines.filter((line) => line.startsWith('#')); + return `${readmeFirst}\n\nREADME was truncated because it was too long. Remaining headers:\n${prunedReadme.join(', ')}`; +} + +const GetActorDefinitionArgsSchema = z.object({ + actorName: z.string() + .describe('Retrieve input, readme, and other details for Actor ID or Actor full name. ' + + 'Actor name is always composed from `username/name`'), + limit: z.number() + .int() + .default(ACTOR_README_MAX_LENGTH) + .describe(`Truncate the README to this limit. Default value is ${ACTOR_README_MAX_LENGTH}.`), +}); + +export const actorDefinitionTool: ToolWrap = { + type: 'internal', + tool: { + name: HelperTools.GET_TOOL_DETAILS, + actorFullName: HelperTools.GET_TOOL_DETAILS, + description: 'Get documentation, readme, input schema and other details about an Actor. ' + + 'For example, when user says, I need to know more about web crawler Actor.' + + 'Get details for an Actor with with Actor ID or Actor full name, i.e. username/name.' + + `Limit the length of the README if needed.`, + inputSchema: zodToJsonSchema(GetActorDefinitionArgsSchema), + ajvValidate: ajv.compile(zodToJsonSchema(GetActorDefinitionArgsSchema)), + call: async (toolArgs) => { + const { args, apifyToken } = toolArgs; + + const parsed = GetActorDefinitionArgsSchema.parse(args); + const v = await getActorDefinition(parsed.actorName, apifyToken, parsed.limit); + if (v && v.input && 'properties' in v.input && v.input) { + const properties = filterSchemaProperties(v.input.properties as { [key: string]: ISchemaProperties }); + v.input.properties = shortenProperties(properties); + } + return { content: [{ type: 'text', text: JSON.stringify(v) }] }; + }, + } as InternalTool, +}; diff --git a/src/tools/helpers.ts b/src/tools/helpers.ts new file mode 100644 index 00000000..2b85ecc7 --- /dev/null +++ b/src/tools/helpers.ts @@ -0,0 +1,66 @@ +import { Ajv } from 'ajv'; +import { z } from 'zod'; +import zodToJsonSchema from 'zod-to-json-schema'; + +import { HelperTools } from '../const.js'; +import type { ActorTool, InternalTool, ToolWrap } from '../types'; +import { getActorsAsTools } from './actor.js'; +import { actorNameToToolName } from './utils.js'; + +const ajv = new Ajv({ coerceTypes: 'array', strict: false }); +export const AddToolArgsSchema = z.object({ + actorName: z.string() + .describe('Add a tool to available tools by Tool ID or tool full name.' + + 'Tool name is always composed from `username/name`'), +}); +export const addTool: ToolWrap = { + type: 'internal', + tool: { + name: HelperTools.ADD_TOOL, + description: 'Add a tool to available tools by Actor ID or Actor name. ' + + 'Do not execute the tool, only add it and list it in available tools. ' + + 'Never run the tool without user consent! ' + + 'For example, add a tool with username/name when user wants to scrape data from a website.', + inputSchema: zodToJsonSchema(AddToolArgsSchema), + ajvValidate: ajv.compile(zodToJsonSchema(AddToolArgsSchema)), + // TODO: I don't like that we are passing apifyMcpServer and mcpServer to the tool + call: async (toolArgs) => { + const { apifyMcpServer, mcpServer, apifyToken, args } = toolArgs; + const parsed = AddToolArgsSchema.parse(args); + const tools = await getActorsAsTools([parsed.actorName], apifyToken); + const toolsAdded = apifyMcpServer.updateTools(tools); + await mcpServer.notification({ method: 'notifications/tools/list_changed' }); + + return { + content: [{ + type: 'text', + text: `Actor added: ${toolsAdded.map((t) => `${(t.tool as ActorTool).actorFullName} (tool name: ${t.tool.name})`).join(', ')}`, + }], + }; + }, + } as InternalTool, +}; +export const RemoveToolArgsSchema = z.object({ + toolName: z.string() + .describe('Tool name to remove from available tools.') + .transform((val) => actorNameToToolName(val)), +}); +export const removeTool: ToolWrap = { + type: 'internal', + tool: { + name: HelperTools.REMOVE_TOOL, + description: 'Remove tool by name from available tools. ' + + 'For example, when user says, I do not need a tool username/name anymore', + inputSchema: zodToJsonSchema(RemoveToolArgsSchema), + ajvValidate: ajv.compile(zodToJsonSchema(RemoveToolArgsSchema)), + // TODO: I don't like that we are passing apifyMcpServer and mcpServer to the tool + call: async (toolArgs) => { + const { apifyMcpServer, mcpServer, args } = toolArgs; + + const parsed = RemoveToolArgsSchema.parse(args); + apifyMcpServer.tools.delete(parsed.toolName); + await mcpServer.notification({ method: 'notifications/tools/list_changed' }); + return { content: [{ type: 'text', text: `Tool ${parsed.toolName} was removed` }] }; + }, + } as InternalTool, +}; diff --git a/src/tools/index.ts b/src/tools/index.ts new file mode 100644 index 00000000..b6f141e0 --- /dev/null +++ b/src/tools/index.ts @@ -0,0 +1,8 @@ +// Import specific tools that are being used +import { callActorGetDataset, getActorsAsTools } from './actor.js'; +import { actorDefinitionTool } from './build.js'; +import { addTool, removeTool } from './helpers.js'; +import { searchTool } from './store_collection.js'; + +// Export only the tools that are being used +export { addTool, removeTool, actorDefinitionTool, searchTool, getActorsAsTools, callActorGetDataset }; diff --git a/src/tools/store_collection.ts b/src/tools/store_collection.ts new file mode 100644 index 00000000..f8c192bb --- /dev/null +++ b/src/tools/store_collection.ts @@ -0,0 +1,95 @@ +import { Ajv } from 'ajv'; +import type { ActorStoreList } from 'apify-client'; +import { z } from 'zod'; +import zodToJsonSchema from 'zod-to-json-schema'; + +import { ApifyClient } from '../apify-client.js'; +import { HelperTools } from '../const.js'; +import type { ActorStorePruned, HelperTool, PricingInfo, ToolWrap } from '../types.js'; + +function pruneActorStoreInfo(response: ActorStoreList): ActorStorePruned { + const stats = response.stats || {}; + const pricingInfo = (response.currentPricingInfo || {}) as PricingInfo; + return { + id: response.id, + name: response.name?.toString() || '', + username: response.username?.toString() || '', + actorFullName: `${response.username}/${response.name}`, + title: response.title?.toString() || '', + description: response.description?.toString() || '', + stats: { + totalRuns: stats.totalRuns, + totalUsers30Days: stats.totalUsers30Days, + publicActorRunStats30Days: 'publicActorRunStats30Days' in stats + ? stats.publicActorRunStats30Days : {}, + }, + currentPricingInfo: { + pricingModel: pricingInfo.pricingModel?.toString() || '', + pricePerUnitUsd: pricingInfo?.pricePerUnitUsd ?? 0, + trialMinutes: pricingInfo?.trialMinutes ?? 0, + }, + url: response.url?.toString() || '', + totalStars: 'totalStars' in response ? (response.totalStars as number) : null, + }; +} + +export async function searchActorsByKeywords( + search: string, + apifyToken: string, + limit: number | undefined = undefined, + offset: number | undefined = undefined, +): Promise { + const client = new ApifyClient({ token: apifyToken }); + const results = await client.store().list({ search, limit, offset }); + return results.items.map((x) => pruneActorStoreInfo(x)); +} + +const ajv = new Ajv({ coerceTypes: 'array', strict: false }); +export const SearchToolArgsSchema = z.object({ + limit: z.number() + .int() + .min(1) + .max(100) + .default(10) + .describe('The maximum number of Actors to return. Default value is 10.'), + offset: z.number() + .int() + .min(0) + .default(0) + .describe('The number of elements that should be skipped at the start. Default value is 0.'), + search: z.string() + .default('') + .describe('String of key words to search by. ' + + 'Searches the title, name, description, username, and readme of an Actor.' + + 'Only key word search is supported, no advanced search.' + + 'Always prefer simple keywords over complex queries.'), + category: z.string() + .default('') + .describe('Filters the results by the specified category.'), +}); +export const searchTool: ToolWrap = { + type: 'internal', + tool: { + name: HelperTools.SEARCH, + actorFullName: HelperTools.SEARCH, + description: `Discover available Actors using full text search using keywords.` + + `Users try to discover Actors using free form query in this case search query needs to be converted to full text search. ` + + `Prefer Actors from Apify as they are generally more reliable and have better support. ` + + `Returns a list of Actors with name, description, run statistics, pricing, starts, and URL. ` + + `You perhaps need to use this tool several times to find the right Actor. ` + + `Limit number of results returned but ensure that relevant results are returned. `, + inputSchema: zodToJsonSchema(SearchToolArgsSchema), + ajvValidate: ajv.compile(zodToJsonSchema(SearchToolArgsSchema)), + call: async (toolArgs) => { + const { args, apifyToken } = toolArgs; + const parsed = SearchToolArgsSchema.parse(args); + const actors = await searchActorsByKeywords( + parsed.search, + apifyToken, + parsed.limit, + parsed.offset, + ); + return { content: actors?.map((item) => ({ type: 'text', text: JSON.stringify(item) })) }; + }, + } as HelperTool, +}; diff --git a/src/actors.ts b/src/tools/utils.ts similarity index 51% rename from src/actors.ts rename to src/tools/utils.ts index c36cf5c8..a9e02688 100644 --- a/src/actors.ts +++ b/src/tools/utils.ts @@ -1,9 +1,5 @@ -import { Ajv } from 'ajv'; -import { ApifyClient } from 'apify-client'; - -import { ACTOR_ADDITIONAL_INSTRUCTIONS, defaults, MAX_DESCRIPTION_LENGTH, ACTOR_README_MAX_LENGTH, ACTOR_ENUM_MAX_LENGTH } from './const.js'; -import { log } from './logger.js'; -import type { ActorDefinitionPruned, ActorDefinitionWithDesc, IActorInputSchema, ISchemaProperties, Tool } from './types.js'; +import { ACTOR_ENUM_MAX_LENGTH, ACTOR_MAX_DESCRIPTION_LENGTH } from '../const.js'; +import type { IActorInputSchema, ISchemaProperties } from '../types.js'; export function actorNameToToolName(actorName: string): string { return actorName @@ -13,172 +9,59 @@ export function actorNameToToolName(actorName: string): string { } /** - * Get actor input schema by actor name. - * First, fetch the actor details to get the default build tag and buildId. - * Then, fetch the build details and return actorName, description, and input schema. - * @param {string} actorIdOrName - Actor ID or Actor full name. - * @param {number} limit - Truncate the README to this limit. - * @returns {Promise} - The actor definition with description or null if not found. - */ -export async function getActorDefinition(actorIdOrName: string, limit: number = ACTOR_README_MAX_LENGTH): Promise { - const client = new ApifyClient({ token: process.env.APIFY_TOKEN }); - const actorClient = client.actor(actorIdOrName); - - try { - // Fetch actor details - const actor = await actorClient.get(); - if (!actor) { - log.error(`Failed to fetch input schema for Actor: ${actorIdOrName}. Actor not found.`); - return null; - } - - // fnesveda: The default build is not necessarily tagged, you can specify any build number as default build. - // There will be a new API endpoint to fetch a default build. - // For now, we'll use the tagged build, it will work for 90% of Actors. Later, we can update this. - const tag = actor.defaultRunOptions?.build || ''; - const buildId = actor.taggedBuilds?.[tag]?.buildId || ''; - - if (!buildId) { - log.error(`Failed to fetch input schema for Actor: ${actorIdOrName}. Build ID not found.`); - return null; - } - // Fetch build details and return the input schema - const buildDetails = await client.build(buildId).get(); - if (buildDetails?.actorDefinition) { - const actorDefinitions = buildDetails?.actorDefinition as ActorDefinitionWithDesc; - actorDefinitions.id = actor.id; - actorDefinitions.readme = truncateActorReadme(actorDefinitions.readme || '', limit); - actorDefinitions.description = actor.description || ''; - actorDefinitions.actorFullName = `${actor.username}/${actor.name}`; - actorDefinitions.defaultRunOptions = actor.defaultRunOptions; - return pruneActorDefinition(actorDefinitions); - } - return null; - } catch (error) { - const errorMessage = `Failed to fetch input schema for Actor: ${actorIdOrName} with error ${error}.`; - log.error(errorMessage); - throw new Error(errorMessage); - } -} - -function pruneActorDefinition(response: ActorDefinitionWithDesc): ActorDefinitionPruned { - return { - id: response.id, - actorFullName: response.actorFullName || '', - buildTag: response?.buildTag || '', - readme: response?.readme || '', - input: response?.input && 'type' in response.input && 'properties' in response.input - ? { ...response.input, - type: response.input.type as string, - properties: response.input.properties as Record } - : undefined, - description: response.description, - defaultRunOptions: response.defaultRunOptions, - }; -} - -/** - * Helper function to shorten the enum list if it is too long. + * Builds nested properties for object types in the schema. * - * @param {string[]} enumList - The list of enum values to be shortened. - * @returns {string[] | undefined} - The shortened enum list or undefined if the list is too long. - */ -export function shortenEnum(enumList: string[]): string[] | undefined { - let charCount = 0; - const resultEnumList = enumList.filter((enumValue) => { - charCount += enumValue.length; - return charCount <= ACTOR_ENUM_MAX_LENGTH; - }); - - return resultEnumList.length > 0 ? resultEnumList : undefined; -} - -/** - * Shortens the description, enum, and items.enum properties of the schema properties. - * @param properties - */ -export function shortenProperties(properties: { [key: string]: ISchemaProperties}): { [key: string]: ISchemaProperties } { - for (const property of Object.values(properties)) { - if (property.description.length > MAX_DESCRIPTION_LENGTH) { - property.description = `${property.description.slice(0, MAX_DESCRIPTION_LENGTH)}...`; - } - - if (property.enum && property.enum?.length > 0) { - property.enum = shortenEnum(property.enum); - } - - if (property.items?.enum && property.items.enum.length > 0) { - property.items.enum = shortenEnum(property.items.enum); - } - } - - return properties; -} - -/** Prune Actor README if it is too long - * If the README is too long - * - We keep the README as it is up to the limit. - * - After the limit, we keep heading only - * - We add a note that the README was truncated because it was too long. - */ -export function truncateActorReadme(readme: string, limit = ACTOR_README_MAX_LENGTH): string { - if (readme.length <= limit) { - return readme; - } - const readmeFirst = readme.slice(0, limit); - const readmeRest = readme.slice(limit); - const lines = readmeRest.split('\n'); - const prunedReadme = lines.filter((line) => line.startsWith('#')); - return `${readmeFirst}\n\nREADME was truncated because it was too long. Remaining headers:\n${prunedReadme.join(', ')}`; -} -/** - * Helps determine the type of items in an array schema property. - * Priority order: explicit type in items > prefill type > default value type > editor type. + * Specifically handles special cases like proxy configuration and request list sources + * by adding predefined nested properties to these object types. + * This is necessary for the agent to correctly infer how to structure object inputs + * when passing arguments to the Actor. * - * Based on JSON schema, the array needs a type, and most of the time Actor input schema does not have this, so we need to infer that. + * For proxy objects (type='object', editor='proxy'), adds 'useApifyProxy' property. + * For request list sources (type='array', editor='requestListSources'), adds URL structure to items. * + * @param {Record} properties - The input schema properties + * @returns {Record} Modified properties with nested properties */ -export function inferArrayItemType(property: ISchemaProperties): string | null { - return property.items?.type - || (Array.isArray(property.prefill) && property.prefill.length > 0 && typeof property.prefill[0]) - || (Array.isArray(property.default) && property.default.length > 0 && typeof property.default[0]) - || (property.editor && getEditorItemType(property.editor)) - || null; - - function getEditorItemType(editor: string): string | null { - const editorTypeMap: Record = { - requestListSources: 'object', - stringList: 'string', - json: 'object', - globs: 'object', - }; - return editorTypeMap[editor] || null; - } -} +export function buildNestedProperties(properties: Record): Record { + const clonedProperties = { ...properties }; -/** - * Add enum values as string to property descriptions. - * - * This is done as a preventive measure to prevent cases where library or agent framework - * does not handle enums or examples based on JSON schema definition. - * - * https://json-schema.org/understanding-json-schema/reference/enum - * https://json-schema.org/understanding-json-schema/reference/annotations - * - * @param properties - */ -function addEnumsToDescriptionsWithExamples(properties: Record): Record { - for (const property of Object.values(properties)) { - if (property.enum && property.enum.length > 0) { - property.description = `${property.description}\nPossible values: ${property.enum.slice(0, 20).join(',')}`; - } - const value = property.prefill ?? property.default; - if (value && !(Array.isArray(value) && value.length === 0)) { - property.examples = Array.isArray(value) ? value : [value]; - property.description = `${property.description}\nExample values: ${JSON.stringify(value)}`; + for (const [propertyName, property] of Object.entries(clonedProperties)) { + if (property.type === 'object' && property.editor === 'proxy') { + clonedProperties[propertyName] = { + ...property, + properties: { + ...property.properties, + useApifyProxy: { + title: 'Use Apify Proxy', + type: 'boolean', + description: 'Whether to use Apify Proxy - ALWAYS SET TO TRUE.', + default: true, + examples: [true], + }, + }, + required: ['useApifyProxy'], + }; + } else if (property.type === 'array' && property.editor === 'requestListSources') { + clonedProperties[propertyName] = { + ...property, + items: { + ...property.items, + type: 'object', + title: 'Request list source', + description: 'Request list source', + properties: { + url: { + title: 'URL', + type: 'string', + description: 'URL of the request list source', + }, + }, + }, + }; } } - return properties; + + return clonedProperties; } /** @@ -188,7 +71,9 @@ function addEnumsToDescriptionsWithExamples(properties: Record} - Modified properties with required fields marked */ -function markInputPropertiesAsRequired(input: IActorInputSchema): Record { +export function markInputPropertiesAsRequired(input: IActorInputSchema): Record { const { required = [], properties } = input; for (const property of Object.keys(properties)) { @@ -243,106 +128,91 @@ function markInputPropertiesAsRequired(input: IActorInputSchema): Record prefill type > default value type > editor type. * - * For proxy objects (type='object', editor='proxy'), adds 'useApifyProxy' property. - * For request list sources (type='array', editor='requestListSources'), adds URL structure to items. + * Based on JSON schema, the array needs a type, and most of the time Actor input schema does not have this, so we need to infer that. * - * @param {Record} properties - The input schema properties - * @returns {Record} Modified properties with nested properties */ -function buildNestedProperties(properties: Record): Record { - const clonedProperties = { ...properties }; +export function inferArrayItemType(property: ISchemaProperties): string | null { + return property.items?.type + || (Array.isArray(property.prefill) && property.prefill.length > 0 && typeof property.prefill[0]) + || (Array.isArray(property.default) && property.default.length > 0 && typeof property.default[0]) + || (property.editor && getEditorItemType(property.editor)) + || null; - for (const [propertyName, property] of Object.entries(clonedProperties)) { - if (property.type === 'object' && property.editor === 'proxy') { - clonedProperties[propertyName] = { - ...property, - properties: { - ...property.properties, - useApifyProxy: { - title: 'Use Apify Proxy', - type: 'boolean', - description: 'Whether to use Apify Proxy - ALWAYS SET TO TRUE.', - default: true, - examples: [true], - }, - }, - required: ['useApifyProxy'], - }; - } else if (property.type === 'array' && property.editor === 'requestListSources') { - clonedProperties[propertyName] = { - ...property, - items: { - ...property.items, - type: 'object', - title: 'Request list source', - description: 'Request list source', - properties: { - url: { - title: 'URL', - type: 'string', - description: 'URL of the request list source', - }, - }, - }, - }; - } + function getEditorItemType(editor: string): string | null { + const editorTypeMap: Record = { + requestListSources: 'object', + stringList: 'string', + json: 'object', + globs: 'object', + }; + return editorTypeMap[editor] || null; } - - return clonedProperties; } /** - * Fetches actor input schemas by Actor IDs or Actor full names and creates MCP tools. + * Add enum values as string to property descriptions. * - * This function retrieves the input schemas for the specified actors and compiles them into MCP tools. - * It uses the AJV library to validate the input schemas. + * This is done as a preventive measure to prevent cases where library or agent framework + * does not handle enums or examples based on JSON schema definition. * - * Tool name can't contain /, so it is replaced with _ + * https://json-schema.org/understanding-json-schema/reference/enum + * https://json-schema.org/understanding-json-schema/reference/annotations * - * The input schema processing workflow: - * 1. Properties are marked as required using markInputPropertiesAsRequired() to add "REQUIRED" prefix to descriptions - * 2. Nested properties are built by analyzing editor type (proxy, requestListSources) using buildNestedProperties() - * 3. Properties are filtered using filterSchemaProperties() - * 4. Properties are shortened using shortenProperties() - * 5. Enums are added to descriptions with examples using addEnumsToDescriptionsWithExamples() + * @param properties + */ +export function addEnumsToDescriptionsWithExamples(properties: Record): Record { + for (const property of Object.values(properties)) { + if (property.enum && property.enum.length > 0) { + property.description = `${property.description}\nPossible values: ${property.enum.slice(0, 20).join(',')}`; + } + const value = property.prefill ?? property.default; + if (value && !(Array.isArray(value) && value.length === 0)) { + property.examples = Array.isArray(value) ? value : [value]; + property.description = `${property.description}\nExample values: ${JSON.stringify(value)}`; + } + } + return properties; +} + +/** + * Helper function to shorten the enum list if it is too long. * - * @param {string[]} actors - An array of actor IDs or Actor full names. - * @returns {Promise} - A promise that resolves to an array of MCP tools. + * @param {string[]} enumList - The list of enum values to be shortened. + * @returns {string[] | undefined} - The shortened enum list or undefined if the list is too long. */ -export async function getActorsAsTools(actors: string[]): Promise { - const ajv = new Ajv({ coerceTypes: 'array', strict: false }); - const results = await Promise.all(actors.map(getActorDefinition)); - const tools = []; - for (const result of results) { - if (result) { - if (result.input && 'properties' in result.input && result.input) { - result.input.properties = markInputPropertiesAsRequired(result.input); - result.input.properties = buildNestedProperties(result.input.properties); - result.input.properties = filterSchemaProperties(result.input.properties); - result.input.properties = shortenProperties(result.input.properties); - result.input.properties = addEnumsToDescriptionsWithExamples(result.input.properties); - } - try { - const memoryMbytes = result.defaultRunOptions?.memoryMbytes || defaults.maxMemoryMbytes; - tools.push({ - name: actorNameToToolName(result.actorFullName), - actorFullName: result.actorFullName, - description: `${result.description} Instructions: ${ACTOR_ADDITIONAL_INSTRUCTIONS}`, - inputSchema: result.input || {}, - ajvValidate: ajv.compile(result.input || {}), - memoryMbytes: memoryMbytes > defaults.maxMemoryMbytes ? defaults.maxMemoryMbytes : memoryMbytes, - }); - } catch (validationError) { - log.error(`Failed to compile AJV schema for Actor: ${result.actorFullName}. Error: ${validationError}`); - } +export function shortenEnum(enumList: string[]): string[] | undefined { + let charCount = 0; + const resultEnumList = enumList.filter((enumValue) => { + charCount += enumValue.length; + return charCount <= ACTOR_ENUM_MAX_LENGTH; + }); + + return resultEnumList.length > 0 ? resultEnumList : undefined; +} + +/** + * Shortens the description, enum, and items.enum properties of the schema properties. + * @param properties + */ +export function shortenProperties(properties: { [key: string]: ISchemaProperties }): { + [key: string]: ISchemaProperties +} { + for (const property of Object.values(properties)) { + if (property.description.length > ACTOR_MAX_DESCRIPTION_LENGTH) { + property.description = `${property.description.slice(0, ACTOR_MAX_DESCRIPTION_LENGTH)}...`; + } + + if (property.enum && property.enum?.length > 0) { + property.enum = shortenEnum(property.enum); + } + + if (property.items?.enum && property.items.enum.length > 0) { + property.items.enum = shortenEnum(property.items.enum); } } - return tools; + + return properties; } diff --git a/src/tsconfig.json b/src/tsconfig.json new file mode 100644 index 00000000..4a8b9089 --- /dev/null +++ b/src/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "./", + "outDir": "../dist", + } +} diff --git a/src/types.ts b/src/types.ts index e62274ec..becf1fc8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,14 +1,8 @@ +import type { Server } from '@modelcontextprotocol/sdk/server/index.js'; import type { ValidateFunction } from 'ajv'; import type { ActorDefaultRunOptions, ActorDefinition } from 'apify-client'; -export type Input = { - actors: string[] | string; - enableAddingActors?: boolean; - enableActorAutoLoading?: boolean; - maxActorMemoryBytes?: number; - debugActor?: string; - debugActorInput?: unknown; -}; +import type { ActorsMcpServer } from './mcp/server.js'; export interface ISchemaProperties { type: string; @@ -52,15 +46,94 @@ export type ActorDefinitionWithDesc = Omit & { export type ActorDefinitionPruned = Pick -export interface Tool { +/** + * Base interface for all tools in the MCP server. + * Contains common properties shared by all tool types. + */ +export interface ToolBase { + /** Unique name/identifier for the tool */ name: string; - actorFullName: string; + /** Description of what the tool does */ description: string; + /** JSON schema defining the tool's input parameters */ inputSchema: object; + /** AJV validation function for the input schema */ ajvValidate: ValidateFunction; +} + +/** + * Interface for Actor-based tools - tools that wrap Apify Actors. + * Extends ToolBase with Actor-specific properties. + */ +export interface ActorTool extends ToolBase { + /** Full name of the Apify Actor (username/name) */ + actorFullName: string; + /** Optional memory limit in MB for the Actor execution */ memoryMbytes?: number; } +/** + * Arguments passed to internal tool calls. + * Contains both the tool arguments and server references. + */ +export type InternalToolArgs = { + /** Arguments passed to the tool */ + args: Record; + /** Reference to the Apify MCP server instance */ + apifyMcpServer: ActorsMcpServer; + /** Reference to the MCP server instance */ + mcpServer: Server; + /** Apify API token */ + apifyToken: string; +} + +/** + * Interface for internal tools - tools implemented directly in the MCP server. + * Extends ToolBase with a call function implementation. + */ +export interface HelperTool extends ToolBase { + /** + * Executes the tool with the given arguments + * @param toolArgs - Arguments and server references + * @returns Promise resolving to the tool's output + */ + call: (toolArgs: InternalToolArgs) => Promise; +} + +/** +* Actorized MCP server tool where this MCP server acts as a proxy. +* Extends ToolBase with tool associated MCP server. +*/ +export interface ActorMCPTool extends ToolBase { + // Origin MCP server tool name, is needed for the tool call + originToolName: string; + // ID of the Actorized MCP server + actorID: string; + /** + * ID of the Actorized MCP server the tool is associated with. + * See getMCPServerID() + */ + serverId: string; + // Connection URL of the Actorized MCP server + serverUrl: string; +} + +/** + * Type discriminator for tools - indicates whether a tool is internal or Actor-based. + */ +export type ToolType = 'internal' | 'actor' | 'actor-mcp'; + +/** + * Wrapper interface that combines a tool with its type discriminator. + * Used to store and manage tools of different types uniformly. + */ +export interface ToolWrap { + /** Type of the tool (internal or actor) */ + type: ToolType; + /** The tool instance */ + tool: ActorTool | HelperTool | ActorMCPTool; +} + // ActorStoreList for actor-search tool export interface ActorStats { totalRuns: number; @@ -86,3 +159,28 @@ export interface ActorStorePruned { url: string; totalStars?: number | null; } + +/** + * Interface for internal tools - tools implemented directly in the MCP server. + * Extends ToolBase with a call function implementation. + */ +export interface InternalTool extends ToolBase { + /** + * Executes the tool with the given arguments + * @param toolArgs - Arguments and server references + * @returns Promise resolving to the tool's output + */ + call: (toolArgs: InternalToolArgs) => Promise; +} + +export type Input = { + actors: string[] | string; + /** + * @deprecated Use `enableAddingActors` instead. + */ + enableActorAutoLoading?: boolean | string; + enableAddingActors?: boolean | string; + maxActorMemoryBytes?: number; + debugActor?: string; + debugActorInput?: unknown; +}; diff --git a/tests/actor-server-test.ts b/tests/actor-server-test.ts new file mode 100644 index 00000000..ddeaa372 --- /dev/null +++ b/tests/actor-server-test.ts @@ -0,0 +1,68 @@ +import type { Server as HttpServer } from 'node:http'; + +import type { Express } from 'express'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import log from '@apify/log'; + +import { createExpressApp } from '../src/actor/server.js'; +import { HelperTools } from '../src/const.js'; +import { ActorsMcpServer } from '../src/mcp/server.js'; + +describe('ApifyMcpServer initialization', () => { + let app: Express; + let server: ActorsMcpServer; + let httpServer: HttpServer; + const testPort = 7357; + const testHost = `http://localhost:${testPort}`; + + beforeEach(async () => { + server = new ActorsMcpServer(); + log.setLevel(log.LEVELS.OFF); + + // Create express app using the proper server setup + app = createExpressApp(testHost, server); + + // Start test server + await new Promise((resolve) => { + httpServer = app.listen(testPort, () => resolve()); + }); + }); + + afterEach(async () => { + await new Promise((resolve) => { + httpServer.close(() => resolve()); + }); + }); + + it('should load actors from query parameters', async () => { + // Test with multiple actors including different username cases + const testActors = ['apify/rag-web-browser', 'apify/instagram-scraper']; + const numberOfHelperTools = 2; + + // Make request to trigger server initialization + const response = await fetch(`${testHost}/?actors=${testActors.join(',')}`); + expect(response.status).toBe(200); + + // Verify loaded tools + const toolNames = server.getToolNames(); + expect(toolNames).toEqual(expect.arrayContaining([ + 'apify-slash-rag-web-browser', + 'apify-slash-instagram-scraper', + ])); + expect(toolNames.length).toBe(testActors.length + numberOfHelperTools); + }); + + it('should enable auto-loading tools when flag is set', async () => { + const response = await fetch(`${testHost}/?enableActorAutoLoading=true`); + expect(response.status).toBe(200); + + const toolNames = server.getToolNames(); + expect(toolNames).toEqual([ + HelperTools.SEARCH, + HelperTools.GET_TOOL_DETAILS, + HelperTools.ADD_TOOL, + HelperTools.REMOVE_TOOL, + ]); + }); +}); diff --git a/tests/actors-test.ts b/tests/actor-test.ts similarity index 96% rename from tests/actors-test.ts rename to tests/actor-test.ts index fafefb97..2fd26f35 100644 --- a/tests/actors-test.ts +++ b/tests/actor-test.ts @@ -1,7 +1,7 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; -import { actorNameToToolName, inferArrayItemType, shortenEnum } from '../src/actors.js'; import { ACTOR_ENUM_MAX_LENGTH } from '../src/const.js'; +import { actorNameToToolName, inferArrayItemType, shortenEnum } from '../src/tools/utils.js'; describe('actors', () => { describe('actorNameToToolName', () => { diff --git a/tests/actor-utils-test.ts b/tests/actor-utils-test.ts new file mode 100644 index 00000000..6389885b --- /dev/null +++ b/tests/actor-utils-test.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from 'vitest'; + +import { parseInputParamsFromUrl } from '../src/mcp/utils.js'; + +describe('parseInputParamsFromUrl', () => { + it('should parse actors from URL query params', () => { + const url = 'https://actors-mcp-server.apify.actor?token=123&actors=apify/web-scraper'; + const result = parseInputParamsFromUrl(url); + expect(result.actors).toEqual(['apify/web-scraper']); + }); + + it('should parse multiple actors from URL', () => { + const url = 'https://actors-mcp-server.apify.actor?actors=apify/instagram-scraper,lukaskrivka/google-maps'; + const result = parseInputParamsFromUrl(url); + expect(result.actors).toEqual(['apify/instagram-scraper', 'lukaskrivka/google-maps']); + }); + + it('should handle URL without query params', () => { + const url = 'https://actors-mcp-server.apify.actor'; + const result = parseInputParamsFromUrl(url); + expect(result.actors).toBeUndefined(); + }); + + it('should parse enableActorAutoLoading flag', () => { + const url = 'https://actors-mcp-server.apify.actor?enableActorAutoLoading=true'; + const result = parseInputParamsFromUrl(url); + expect(result.enableAddingActors).toBe(true); + }); + + it('should parse enableAddingActors flag', () => { + const url = 'https://actors-mcp-server.apify.actor?enableAddingActors=true'; + const result = parseInputParamsFromUrl(url); + expect(result.enableAddingActors).toBe(true); + }); + + it('should parse enableAddingActors flag', () => { + const url = 'https://actors-mcp-server.apify.actor?enableAddingActors=false'; + const result = parseInputParamsFromUrl(url); + expect(result.enableAddingActors).toBe(false); + }); + + it('should handle actors as string parameter', () => { + const url = 'https://actors-mcp-server.apify.actor?actors=apify/rag-web-browser'; + const result = parseInputParamsFromUrl(url); + expect(result.actors).toEqual(['apify/rag-web-browser']); + }); +}); diff --git a/tests/input.test.ts b/tests/input.test.ts index 284dd5c8..5a291960 100644 --- a/tests/input.test.ts +++ b/tests/input.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { processInput } from '../src/input.js'; import type { Input } from '../src/types.js'; @@ -8,7 +8,7 @@ describe('processInput', () => { const input: Partial = { actors: 'actor1, actor2,actor3', }; - const processed = await processInput(input); + const processed = processInput(input); expect(processed.actors).toEqual(['actor1', 'actor2', 'actor3']); }); @@ -16,7 +16,7 @@ describe('processInput', () => { const input: Partial = { actors: ['actor1', 'actor2', 'actor3'], }; - const processed = await processInput(input); + const processed = processInput(input); expect(processed.actors).toEqual(['actor1', 'actor2', 'actor3']); }); @@ -25,7 +25,7 @@ describe('processInput', () => { actors: ['actor1'], enableActorAutoLoading: true, }; - const processed = await processInput(input); + const processed = processInput(input); expect(processed.enableAddingActors).toBe(true); }); @@ -35,7 +35,7 @@ describe('processInput', () => { enableActorAutoLoading: true, enableAddingActors: false, }; - const processed = await processInput(input); + const processed = processInput(input); expect(processed.enableAddingActors).toBe(false); }); @@ -43,7 +43,7 @@ describe('processInput', () => { const input: Partial = { actors: ['actor1'], }; - const processed = await processInput(input); + const processed = processInput(input); expect(processed.enableAddingActors).toBe(false); }); }); diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index c5811e85..16c0e4e8 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -1,14 +1,9 @@ { - "extends": "./tsconfig.json", - "include": [ - "src/**/*.ts", - "tests/**/*.ts", - "*.ts", - "*.js", - ".eslintrc.js" - ], - "exclude": [ - "node_modules", - "dist" - ] + "extends": "./tsconfig.json", + "include": [ + "src", + "test", + "tests", + "vitest.config.ts" + ], } diff --git a/tsconfig.json b/tsconfig.json index fb02aa71..8288461e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,7 @@ { - "extends": "@apify/tsconfig", - "compilerOptions": { - "module": "ESNext", - "target": "ESNext", - "outDir": "dist", - "moduleResolution": "node", - "noUnusedLocals": false, - "lib": ["ES2022"], - "skipLibCheck": true, - "typeRoots": ["./types", "./node_modules/@types"], - "strict": true - }, - "include": ["./src/**/*"], - "exclude": ["node_modules"] + "extends": "@apify/tsconfig", + "compilerOptions": { + "module": "ES2022", + "skipLibCheck": true, + }, }