diff --git a/packages/mcp-server-mysql/.gitignore b/packages/mcp-server-mysql/.gitignore new file mode 100644 index 00000000000..d44104a14e8 --- /dev/null +++ b/packages/mcp-server-mysql/.gitignore @@ -0,0 +1,29 @@ +# Dependencies +node_modules/ + +# Build output +dist/ +*.tsbuildinfo + +# IDE +.vscode/ +.idea/ + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment files +.env +.env.local +.env.*.local + +# OS files +.DS_Store +Thumbs.db + +# Test coverage +coverage/ +.nyc_output/ \ No newline at end of file diff --git a/packages/mcp-server-mysql/README.md b/packages/mcp-server-mysql/README.md new file mode 100644 index 00000000000..237c7a9e129 --- /dev/null +++ b/packages/mcp-server-mysql/README.md @@ -0,0 +1,168 @@ +# MySQL MCP Server + +A Model Context Protocol (MCP) server that provides MySQL database operations. + +## Features + +- Execute SELECT queries safely +- Execute INSERT, UPDATE, DELETE, and DDL operations +- List databases and tables +- Describe table structures +- Test database connections +- Connection pooling for efficient resource usage + +## Installation + +```bash +npm install @roo-code/mcp-server-mysql +``` + +## Configuration + +The MySQL MCP server requires the following environment variables: + +- `MYSQL_HOST` - MySQL server host (default: `localhost`) +- `MYSQL_PORT` - MySQL server port (default: `3306`) +- `MYSQL_USER` - MySQL username (default: `root`) +- `MYSQL_PASSWORD` - MySQL password (default: empty string) +- `MYSQL_DATABASE` - Default database to use (optional) + +## Available Tools + +### `query` + +Execute SELECT queries on the MySQL database. + +**Parameters:** + +- `query` (string, required): The SELECT query to execute +- `database` (string, optional): Database to use (overrides default) + +**Example:** + +```json +{ + "query": "SELECT * FROM users WHERE active = 1", + "database": "myapp" +} +``` + +### `execute` + +Execute non-SELECT queries (INSERT, UPDATE, DELETE, CREATE, etc.). + +**Parameters:** + +- `query` (string, required): The SQL query to execute +- `database` (string, optional): Database to use (overrides default) + +**Example:** + +```json +{ + "query": "INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com')", + "database": "myapp" +} +``` + +### `list_databases` + +List all databases in the MySQL server. + +**No parameters required.** + +### `list_tables` + +List all tables in a specific database. + +**Parameters:** + +- `database` (string, required): The database name + +**Example:** + +```json +{ + "database": "myapp" +} +``` + +### `describe_table` + +Get the structure of a table. + +**Parameters:** + +- `table` (string, required): The table name +- `database` (string, optional): The database name (uses default if not specified) + +**Example:** + +```json +{ + "table": "users", + "database": "myapp" +} +``` + +### `test_connection` + +Test the MySQL connection and get server information. + +**No parameters required.** + +## Usage with Roo Code + +To use this MCP server with Roo Code, add it to your MCP settings configuration: + +```json +{ + "mcpServers": { + "mysql": { + "command": "node", + "args": ["path/to/@roo-code/mcp-server-mysql/dist/index.js"], + "env": { + "MYSQL_HOST": "localhost", + "MYSQL_PORT": "3306", + "MYSQL_USER": "your_username", + "MYSQL_PASSWORD": "your_password", + "MYSQL_DATABASE": "your_default_db" + } + } + } +} +``` + +## Security Considerations + +- The `query` tool only allows SELECT, SHOW, and DESCRIBE queries +- The `execute` tool is for all other operations (INSERT, UPDATE, DELETE, etc.) +- Always use parameterized queries when building dynamic SQL +- Ensure proper access controls are in place at the MySQL server level +- Store credentials securely and never commit them to version control + +## Development + +```bash +# Install dependencies +npm install + +# Build the project +npm run build + +# Run in development mode +npm run dev + +# Run tests +npm test + +# Type checking +npm run typecheck + +# Linting +npm run lint +``` + +## License + +MIT diff --git a/packages/mcp-server-mysql/eslint.config.mjs b/packages/mcp-server-mysql/eslint.config.mjs new file mode 100644 index 00000000000..19270d6b09f --- /dev/null +++ b/packages/mcp-server-mysql/eslint.config.mjs @@ -0,0 +1,4 @@ +import { config } from "@roo-code/config-eslint/base" + +/** @type {import("eslint").Linter.Config} */ +export default [...config] \ No newline at end of file diff --git a/packages/mcp-server-mysql/package.json b/packages/mcp-server-mysql/package.json new file mode 100644 index 00000000000..b012c3c7058 --- /dev/null +++ b/packages/mcp-server-mysql/package.json @@ -0,0 +1,43 @@ +{ + "name": "@roo-code/mcp-server-mysql", + "version": "0.1.0", + "description": "MySQL MCP server for Roo Code", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "dev": "tsx src/index.ts", + "start": "node dist/index.js", + "test": "vitest run", + "test:watch": "vitest", + "lint": "eslint src --ext .ts", + "typecheck": "tsc --noEmit" + }, + "keywords": [ + "mcp", + "mysql", + "database", + "model-context-protocol" + ], + "author": "Roo Code Inc", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.9.0", + "mysql2": "^3.11.5", + "zod": "^3.24.1" + }, + "devDependencies": { + "@roo-code/config-eslint": "workspace:*", + "@types/node": "^22.10.5", + "@typescript-eslint/eslint-plugin": "^8.20.0", + "@typescript-eslint/parser": "^8.20.0", + "eslint": "^9.18.0", + "tsx": "^4.19.2", + "typescript": "^5.7.3", + "vitest": "^2.1.8" + }, + "engines": { + "node": ">=18" + } +} diff --git a/packages/mcp-server-mysql/src/index.test.ts b/packages/mcp-server-mysql/src/index.test.ts new file mode 100644 index 00000000000..3dc861731e4 --- /dev/null +++ b/packages/mcp-server-mysql/src/index.test.ts @@ -0,0 +1,43 @@ +import { describe, it, expect, beforeAll, afterAll, vi } from "vitest" +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" + +// Mock the mysql2/promise module +vi.mock("mysql2/promise", () => ({ + default: { + createPool: vi.fn(() => ({ + getConnection: vi.fn(() => ({ + execute: vi.fn(() => [[{ Database: "test_db" }], [{ name: "Database" }]]), + ping: vi.fn(), + changeUser: vi.fn(), + release: vi.fn(), + })), + })), + }, +})) + +describe("MySQL MCP Server", () => { + it("should create server instance", () => { + const server = new McpServer({ + name: "mysql-server", + version: "0.1.0", + description: "MySQL database operations via MCP", + }) + + expect(server).toBeDefined() + }) + + it("should have required tools", async () => { + const { server } = await import("./index.js") + + // Check if tools are registered + const tools = server.getTools() + const toolNames = tools.map((tool) => tool.name) + + expect(toolNames).toContain("query") + expect(toolNames).toContain("execute") + expect(toolNames).toContain("list_databases") + expect(toolNames).toContain("list_tables") + expect(toolNames).toContain("describe_table") + expect(toolNames).toContain("test_connection") + }) +}) diff --git a/packages/mcp-server-mysql/src/index.ts b/packages/mcp-server-mysql/src/index.ts new file mode 100644 index 00000000000..63902a243d1 --- /dev/null +++ b/packages/mcp-server-mysql/src/index.ts @@ -0,0 +1,393 @@ +#!/usr/bin/env node +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js" +import { z } from "zod" +import mysql from "mysql2/promise" +import { Connection, RowDataPacket, FieldPacket } from "mysql2/promise" + +// Environment variables for MySQL connection +const MYSQL_HOST = process.env.MYSQL_HOST || "localhost" +const MYSQL_PORT = parseInt(process.env.MYSQL_PORT || "3306") +const MYSQL_USER = process.env.MYSQL_USER || "root" +const MYSQL_PASSWORD = process.env.MYSQL_PASSWORD || "" +const MYSQL_DATABASE = process.env.MYSQL_DATABASE + +// Connection pool to manage MySQL connections +let connectionPool: mysql.Pool | null = null + +// Create an MCP server +const server = new McpServer({ + name: "mysql-server", + version: "0.1.0", + description: "MySQL database operations via MCP", +}) + +// Initialize connection pool +async function initializePool() { + if (!connectionPool) { + connectionPool = mysql.createPool({ + host: MYSQL_HOST, + port: MYSQL_PORT, + user: MYSQL_USER, + password: MYSQL_PASSWORD, + database: MYSQL_DATABASE, + waitForConnections: true, + connectionLimit: 10, + queueLimit: 0, + enableKeepAlive: true, + keepAliveInitialDelay: 0, + }) + } + return connectionPool +} + +// Helper function to format query results +function formatQueryResult(rows: RowDataPacket[], fields: FieldPacket[]): string { + if (rows.length === 0) { + return "No results found." + } + + // Get column names + const columns = fields.map((field) => field.name) + + // Create a formatted table + let result = columns.join(" | ") + "\n" + result += columns.map((col) => "-".repeat(col.length)).join("-|-") + "\n" + + // Add rows + rows.forEach((row) => { + result += columns.map((col) => String(row[col] ?? "NULL")).join(" | ") + "\n" + }) + + return result +} + +// Tool: Execute a SELECT query +server.tool( + "query", + { + description: "Execute a SELECT query on the MySQL database", + inputSchema: z.object({ + query: z.string().describe("The SELECT query to execute"), + database: z.string().optional().describe("Database to use (overrides default)"), + }), + }, + async ({ query, database }) => { + try { + // Validate that it's a SELECT query + const normalizedQuery = query.trim().toUpperCase() + if ( + !normalizedQuery.startsWith("SELECT") && + !normalizedQuery.startsWith("SHOW") && + !normalizedQuery.startsWith("DESCRIBE") + ) { + return { + content: [ + { + type: "text", + text: "Error: Only SELECT, SHOW, and DESCRIBE queries are allowed with this tool. Use 'execute' tool for other operations.", + }, + ], + isError: true, + } + } + + const pool = await initializePool() + const connection = await pool.getConnection() + + try { + if (database) { + await connection.changeUser({ database }) + } + + const [rows, fields] = (await connection.execute(query)) as [RowDataPacket[], FieldPacket[]] + const formattedResult = formatQueryResult(rows, fields) + + return { + content: [ + { + type: "text", + text: formattedResult, + }, + ], + } + } finally { + connection.release() + } + } catch (error) { + return { + content: [ + { + type: "text", + text: `MySQL Error: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + } + } + }, +) + +// Tool: Execute non-SELECT queries (INSERT, UPDATE, DELETE, CREATE, etc.) +server.tool( + "execute", + { + description: "Execute a non-SELECT query on the MySQL database (INSERT, UPDATE, DELETE, CREATE, etc.)", + inputSchema: z.object({ + query: z.string().describe("The SQL query to execute"), + database: z.string().optional().describe("Database to use (overrides default)"), + }), + }, + async ({ query, database }) => { + try { + // Validate that it's NOT a SELECT query + const normalizedQuery = query.trim().toUpperCase() + if (normalizedQuery.startsWith("SELECT")) { + return { + content: [ + { + type: "text", + text: "Error: Use the 'query' tool for SELECT queries. This tool is for INSERT, UPDATE, DELETE, CREATE, and other non-SELECT operations.", + }, + ], + isError: true, + } + } + + const pool = await initializePool() + const connection = await pool.getConnection() + + try { + if (database) { + await connection.changeUser({ database }) + } + + const [result] = await connection.execute(query) + + // Format the result based on the operation type + let message = "Query executed successfully.\n" + if ("affectedRows" in result) { + message += `Affected rows: ${result.affectedRows}\n` + } + if ("insertId" in result) { + message += `Insert ID: ${result.insertId}\n` + } + if ("changedRows" in result) { + message += `Changed rows: ${result.changedRows}\n` + } + + return { + content: [ + { + type: "text", + text: message, + }, + ], + } + } finally { + connection.release() + } + } catch (error) { + return { + content: [ + { + type: "text", + text: `MySQL Error: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + } + } + }, +) + +// Tool: List databases +server.tool( + "list_databases", + { + description: "List all databases in the MySQL server", + }, + async () => { + try { + const pool = await initializePool() + const connection = await pool.getConnection() + + try { + const [rows] = (await connection.execute("SHOW DATABASES")) as [RowDataPacket[], FieldPacket[]] + const databases = rows.map((row) => row.Database || row.database).join("\n") + + return { + content: [ + { + type: "text", + text: `Available databases:\n${databases}`, + }, + ], + } + } finally { + connection.release() + } + } catch (error) { + return { + content: [ + { + type: "text", + text: `MySQL Error: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + } + } + }, +) + +// Tool: List tables in a database +server.tool( + "list_tables", + { + description: "List all tables in a database", + inputSchema: z.object({ + database: z.string().describe("The database name"), + }), + }, + async ({ database }) => { + try { + const pool = await initializePool() + const connection = await pool.getConnection() + + try { + await connection.changeUser({ database }) + const [rows] = (await connection.execute("SHOW TABLES")) as [RowDataPacket[], FieldPacket[]] + const tables = rows.map((row) => Object.values(row)[0]).join("\n") + + return { + content: [ + { + type: "text", + text: `Tables in ${database}:\n${tables}`, + }, + ], + } + } finally { + connection.release() + } + } catch (error) { + return { + content: [ + { + type: "text", + text: `MySQL Error: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + } + } + }, +) + +// Tool: Describe table structure +server.tool( + "describe_table", + { + description: "Get the structure of a table", + inputSchema: z.object({ + table: z.string().describe("The table name"), + database: z.string().optional().describe("The database name (uses default if not specified)"), + }), + }, + async ({ table, database }) => { + try { + const pool = await initializePool() + const connection = await pool.getConnection() + + try { + if (database) { + await connection.changeUser({ database }) + } + + const [rows, fields] = (await connection.execute(`DESCRIBE ${table}`)) as [ + RowDataPacket[], + FieldPacket[], + ] + const formattedResult = formatQueryResult(rows, fields) + + return { + content: [ + { + type: "text", + text: `Structure of table ${table}:\n${formattedResult}`, + }, + ], + } + } finally { + connection.release() + } + } catch (error) { + return { + content: [ + { + type: "text", + text: `MySQL Error: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + } + } + }, +) + +// Tool: Test connection +server.tool( + "test_connection", + { + description: "Test the MySQL connection", + }, + async () => { + try { + const pool = await initializePool() + const connection = await pool.getConnection() + + try { + await connection.ping() + const [rows] = (await connection.execute("SELECT VERSION() as version, DATABASE() as current_db")) as [ + RowDataPacket[], + FieldPacket[], + ] + const info = rows[0] + + return { + content: [ + { + type: "text", + text: `MySQL connection successful!\nVersion: ${info.version}\nCurrent database: ${info.current_db || "None"}\nHost: ${MYSQL_HOST}:${MYSQL_PORT}`, + }, + ], + } + } finally { + connection.release() + } + } catch (error) { + return { + content: [ + { + type: "text", + text: `MySQL connection failed: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + } + } + }, +) + +// Start the server +async function main() { + const transport = new StdioServerTransport() + await server.connect(transport) + console.error("MySQL MCP server running on stdio") +} + +main().catch((error) => { + console.error("Failed to start MySQL MCP server:", error) + process.exit(1) +}) diff --git a/packages/mcp-server-mysql/tsconfig.json b/packages/mcp-server-mysql/tsconfig.json new file mode 100644 index 00000000000..d6921b50c94 --- /dev/null +++ b/packages/mcp-server-mysql/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../config-typescript/base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "lib": ["ES2022"], + "types": ["node"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 14e33596d1e..0e1470ad0e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -427,7 +427,7 @@ importers: version: 0.13.0 drizzle-orm: specifier: ^0.44.1 - version: 0.44.1(@libsql/client@0.15.8)(better-sqlite3@11.10.0)(gel@2.1.0)(postgres@3.4.7) + version: 0.44.1(@libsql/client@0.15.8)(better-sqlite3@11.10.0)(gel@2.1.0)(mysql2@3.14.2)(postgres@3.4.7) execa: specifier: ^9.6.0 version: 9.6.0 @@ -506,6 +506,43 @@ importers: specifier: ^3.2.3 version: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.57)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + packages/mcp-server-mysql: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ^1.9.0 + version: 1.12.0 + mysql2: + specifier: ^3.11.5 + version: 3.14.2 + zod: + specifier: ^3.24.1 + version: 3.25.61 + devDependencies: + '@roo-code/config-eslint': + specifier: workspace:* + version: link:../config-eslint + '@types/node': + specifier: ^22.10.5 + version: 22.15.29 + '@typescript-eslint/eslint-plugin': + specifier: ^8.20.0 + version: 8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^8.20.0 + version: 8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + eslint: + specifier: ^9.18.0 + version: 9.28.0(jiti@2.4.2) + tsx: + specifier: ^4.19.2 + version: 4.19.4 + typescript: + specifier: ^5.7.3 + version: 5.8.3 + vitest: + specifier: ^2.1.8 + version: 2.1.9(@types/node@22.15.29)(jsdom@26.1.0)(lightningcss@1.30.1) + packages/telemetry: dependencies: '@roo-code/types': @@ -3878,9 +3915,6 @@ packages: '@types/node@20.17.57': resolution: {integrity: sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==} - '@types/node@20.19.1': - resolution: {integrity: sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==} - '@types/node@22.15.29': resolution: {integrity: sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==} @@ -4022,9 +4056,23 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + '@vitest/expect@2.1.9': + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/mocker@2.1.9': + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: @@ -4036,15 +4084,27 @@ packages: vite: optional: true + '@vitest/pretty-format@2.1.9': + resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} + '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/runner@2.1.9': + resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} + '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + '@vitest/snapshot@2.1.9': + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + '@vitest/snapshot@3.2.4': resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + '@vitest/spy@2.1.9': + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} @@ -4053,6 +4113,9 @@ packages: peerDependencies: vitest: 3.2.4 + '@vitest/utils@2.1.9': + resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} @@ -4306,6 +4369,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + axios@1.9.0: resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} @@ -5097,6 +5164,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -5904,6 +5975,9 @@ packages: engines: {node: '>= 18.0.0'} hasBin: true + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -6420,6 +6494,9 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -6987,6 +7064,9 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -7024,6 +7104,10 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + lru.min@1.1.2: + resolution: {integrity: sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + lucide-react@0.518.0: resolution: {integrity: sha512-kFg34uQqnVl/7HwAiigxPSpj//43VIVHQbMygQPtS1yT4btMXHCWUipHcgcXHD2pm1Z2nUBA/M+Vnh/YmWXQUw==} peerDependencies: @@ -7374,9 +7458,17 @@ packages: mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + mysql2@3.14.2: + resolution: {integrity: sha512-YD6mZMeoypmheHT6b2BrVmQFvouEpRICuvPIREulx2OvP1xAxxeqkMQqZSTBefv0PiOBKGYFa2zQtY+gf/4eQw==} + engines: {node: '>= 8.0'} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + nano-css@5.6.2: resolution: {integrity: sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==} peerDependencies: @@ -7771,6 +7863,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -8452,6 +8547,9 @@ packages: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + serialize-error@12.0.0: resolution: {integrity: sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==} engines: {node: '>=18'} @@ -8639,6 +8737,10 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + stack-generator@2.0.10: resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} @@ -8952,10 +9054,18 @@ packages: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + tinyrainbow@2.0.0: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + tinyspy@4.0.3: resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} engines: {node: '>=14.0.0'} @@ -9384,11 +9494,47 @@ packages: victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true + vite@5.4.19: + resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + vite@6.3.5: resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -9429,6 +9575,31 @@ packages: yaml: optional: true + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vitest@3.2.4: resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -11064,7 +11235,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.57 + '@types/node': 22.15.29 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -13044,7 +13215,7 @@ snapshots: '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.17.57 + '@types/node': 22.15.29 '@types/hast@3.0.4': dependencies: @@ -13097,7 +13268,7 @@ snapshots: '@types/node-fetch@2.6.12': dependencies: - '@types/node': 20.17.57 + '@types/node': 22.15.29 form-data: 4.0.2 '@types/node-ipc@9.2.3': @@ -13120,10 +13291,6 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/node@20.19.1': - dependencies: - undici-types: 6.21.0 - '@types/node@22.15.29': dependencies: undici-types: 6.21.0 @@ -13157,11 +13324,11 @@ snapshots: '@types/stream-chain@2.1.0': dependencies: - '@types/node': 20.19.1 + '@types/node': 22.15.29 '@types/stream-json@1.7.8': dependencies: - '@types/node': 20.19.1 + '@types/node': 22.15.29 '@types/stream-chain': 2.1.0 '@types/string-similarity@4.0.2': {} @@ -13187,7 +13354,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 20.19.1 + '@types/node': 22.15.29 optional: true '@types/yargs-parser@21.0.3': {} @@ -13198,7 +13365,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.17.57 + '@types/node': 22.15.29 optional: true '@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': @@ -13218,6 +13385,23 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.32.1 + '@typescript-eslint/type-utils': 8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.32.1 + eslint: 9.28.0(jiti@2.4.2) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.32.1 @@ -13230,6 +13414,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.32.1 + '@typescript-eslint/types': 8.32.1 + '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.32.1 + debug: 4.4.1(supports-color@8.1.1) + eslint: 9.28.0(jiti@2.4.2) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.32.1': dependencies: '@typescript-eslint/types': 8.32.1 @@ -13246,6 +13442,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + debug: 4.4.1(supports-color@8.1.1) + eslint: 9.28.0(jiti@2.4.2) + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.32.1': {} '@typescript-eslint/typescript-estree@8.32.1(typescript@5.8.3)': @@ -13273,6 +13480,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.32.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0(jiti@2.4.2)) + '@typescript-eslint/scope-manager': 8.32.1 + '@typescript-eslint/types': 8.32.1 + '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3) + eslint: 9.28.0(jiti@2.4.2) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.32.1': dependencies: '@typescript-eslint/types': 8.32.1 @@ -13299,6 +13517,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/expect@2.1.9': + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.2.0 + tinyrainbow: 1.2.0 + '@vitest/expect@3.2.4': dependencies: '@types/chai': 5.2.2 @@ -13307,6 +13532,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 + '@vitest/mocker@2.1.9(vite@5.4.19(@types/node@22.15.29)(lightningcss@1.30.1))': + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 5.4.19(@types/node@22.15.29)(lightningcss@1.30.1) + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.2.4 @@ -13331,22 +13564,41 @@ snapshots: optionalDependencies: vite: 6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + '@vitest/pretty-format@2.1.9': + dependencies: + tinyrainbow: 1.2.0 + '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 + '@vitest/runner@2.1.9': + dependencies: + '@vitest/utils': 2.1.9 + pathe: 1.1.2 + '@vitest/runner@3.2.4': dependencies: '@vitest/utils': 3.2.4 pathe: 2.0.3 strip-literal: 3.0.0 + '@vitest/snapshot@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.17 + pathe: 1.1.2 + '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 magic-string: 0.30.17 pathe: 2.0.3 + '@vitest/spy@2.1.9': + dependencies: + tinyspy: 3.0.2 + '@vitest/spy@3.2.4': dependencies: tinyspy: 4.0.3 @@ -13362,6 +13614,12 @@ snapshots: tinyrainbow: 2.0.0 vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.15.29)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + '@vitest/utils@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + loupe: 3.1.4 + tinyrainbow: 1.2.0 + '@vitest/utils@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 @@ -13681,6 +13939,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + aws-ssl-profiles@1.1.2: {} + axios@1.9.0: dependencies: follow-redirects: 1.15.9 @@ -14512,6 +14772,8 @@ snapshots: delayed-stream@1.0.0: {} + denque@2.1.0: {} + depd@2.0.0: {} dequal@2.0.3: {} @@ -14597,11 +14859,12 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.44.1(@libsql/client@0.15.8)(better-sqlite3@11.10.0)(gel@2.1.0)(postgres@3.4.7): + drizzle-orm@0.44.1(@libsql/client@0.15.8)(better-sqlite3@11.10.0)(gel@2.1.0)(mysql2@3.14.2)(postgres@3.4.7): optionalDependencies: '@libsql/client': 0.15.8 better-sqlite3: 11.10.0 gel: 2.1.0 + mysql2: 3.14.2 postgres: 3.4.7 duck@0.1.12: @@ -15458,6 +15721,10 @@ snapshots: - supports-color optional: true + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -16022,6 +16289,8 @@ snapshots: is-promise@4.0.0: {} + is-property@1.0.2: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -16160,7 +16429,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.57 + '@types/node': 22.15.29 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -16595,6 +16864,8 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 + long@5.3.2: {} + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -16631,6 +16902,8 @@ snapshots: lru-cache@7.18.3: {} + lru.min@1.1.2: {} + lucide-react@0.518.0(react@18.3.1): dependencies: react: 18.3.1 @@ -17235,12 +17508,28 @@ snapshots: mute-stream@0.0.8: {} + mysql2@3.14.2: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.3.2 + lru.min: 1.1.2 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 + named-placeholders@1.1.3: + dependencies: + lru-cache: 7.18.3 + nano-css@5.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -17676,6 +17965,8 @@ snapshots: path-type@4.0.0: {} + pathe@1.1.2: {} + pathe@2.0.3: {} pathval@2.0.0: {} @@ -18503,6 +18794,8 @@ snapshots: transitivePeerDependencies: - supports-color + seq-queue@0.0.5: {} + serialize-error@12.0.0: dependencies: type-fest: 4.41.0 @@ -18738,6 +19031,8 @@ snapshots: sprintf-js@1.1.3: {} + sqlstring@2.3.3: {} + stack-generator@2.0.10: dependencies: stackframe: 1.3.4 @@ -19096,8 +19391,12 @@ snapshots: tinypool@1.1.1: {} + tinyrainbow@1.2.0: {} + tinyrainbow@2.0.0: {} + tinyspy@3.0.2: {} + tinyspy@4.0.3: {} tldts-core@6.1.86: {} @@ -19561,6 +19860,24 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + vite-node@2.1.9(@types/node@22.15.29)(lightningcss@1.30.1): + dependencies: + cac: 6.7.14 + debug: 4.4.1(supports-color@8.1.1) + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.19(@types/node@22.15.29)(lightningcss@1.30.1) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-node@3.2.4(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): dependencies: cac: 6.7.14 @@ -19624,6 +19941,16 @@ snapshots: - tsx - yaml + vite@5.4.19(@types/node@22.15.29)(lightningcss@1.30.1): + dependencies: + esbuild: 0.25.5 + postcss: 8.5.4 + rollup: 4.40.2 + optionalDependencies: + '@types/node': 22.15.29 + fsevents: 2.3.3 + lightningcss: 1.30.1 + vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): dependencies: esbuild: 0.25.5 @@ -19672,6 +19999,42 @@ snapshots: tsx: 4.19.4 yaml: 2.8.0 + vitest@2.1.9(@types/node@22.15.29)(jsdom@26.1.0)(lightningcss@1.30.1): + dependencies: + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.19(@types/node@22.15.29)(lightningcss@1.30.1)) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.2.0 + debug: 4.4.1(supports-color@8.1.1) + expect-type: 1.2.1 + magic-string: 0.30.17 + pathe: 1.1.2 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.19(@types/node@22.15.29)(lightningcss@1.30.1) + vite-node: 2.1.9(@types/node@22.15.29)(lightningcss@1.30.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.15.29 + jsdom: 26.1.0 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vitest@3.2.4(@types/debug@4.1.12)(@types/node@20.17.50)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): dependencies: '@types/chai': 5.2.2