├── .gitignore ├── LICENSE ├── README.md ├── assets └── demo.png ├── dist ├── inc │ ├── json-config.js │ ├── main-mcp-server.js │ ├── main-server.js │ ├── server-arguments.js │ ├── wrapped-servers.js │ └── zod-utils.js ├── index.js └── server-arguments.js ├── package-lock.json ├── package.json ├── src ├── inc │ ├── json-config.ts │ ├── main-mcp-server.ts │ ├── server-arguments.ts │ ├── wrapped-servers.ts │ └── zod-utils.ts └── index.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | .idea/ 3 | 4 | # Local Dev Environment 5 | /local-setups/ 6 | /desktop.ini 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Enrico Ballardini 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multiverse MCP Server 2 | 3 | A middleware server that enables multiple isolated instances of the same MCP servers to coexist independently with unique namespaces and configurations. 4 | 5 | The Multiverse MCP Server creates isolated operational spaces where identical MCP servers can run simultaneously without conflicts. Each "universe" maintains its own configuration, filesystem access, and function naming, enabling developers to run multiple instances of the same server type while maintaining complete separation between different contexts or projects. 6 | 7 | ## Key Features 8 | 9 | ### Run Multiple Instances 10 | Run multiple instances of the same MCP server type independently and simultaneously. Each instance operates in its own isolated universe with separate configurations. This enables scenarios like: 11 | - Multiple MySQL servers `mcp-server-mysql` pointing to different databases 12 | - Multiple Git servers `mcp-server-git` with different Personal Access Tokens 13 | - Multiple filesystem servers `mcp-server-filesystem` accessing different root paths 14 | 15 | ### Automatic Server Restart 16 | Register your MCP server with file watching capability during development. When enabled, the server automatically detects changes in the specified directory and performs a graceful restart, making development and testing seamless. 17 | 18 | ### JSON-based Configuration System 19 | Define your multiverse setup using a simple and flexible JSON configuration format. Each server instance can be configured with its own: 20 | - Command and arguments 21 | - Environment variables 22 | - Path resolution rules 23 | - File watching settings 24 | 25 | ## Installation 26 | 27 | First, ensure you've downloaded and installed the [Claude Desktop app](https://claude.ai/download) and you have npm installed. 28 | 29 | Next, add this entry to your `claude_desktop_config.json` 30 | - on Mac, found at `~/Library/Application\ Support/Claude/claude_desktop_config.json` 31 | - on Windows, found at `C:\Users\\AppData\Roaming\Claude\claude_desktop_config.json` 32 | 33 | Now add how many multiverse servers you want to run. For example, if you want to run two instances of `mcp-server-multiverse`, one for your job and one for your side project, you can add the following configuration: 34 | 35 | ```json 36 | { 37 | "mcpServers": { 38 | "job-multiverse": { 39 | "command": "npx", 40 | "args": [ 41 | "-y", 42 | "@lamemind/mcp-server-multiverse@latest", 43 | "/path/to/your/job-multiverse.json" 44 | ] 45 | }, 46 | "side-project-multiverse": { 47 | "command": "npx", 48 | "args": [ 49 | "-y", 50 | "@lamemind/mcp-server-multiverse@latest", 51 | "/path/to/your/side-project-multiverse.json" 52 | ] 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | This config allows Claude Desktop to automatically start the `mcp-server-multiverse` instances when you start the app. 59 | 60 | ![demo.png](assets/demo.png) 61 | 62 | ## Configuration Examples 63 | 64 | ### Create two isolated instances of `mcp-server-mysql` with different databases 65 | 66 | Your `job-multiverse.json` file 67 | ~~~JSON 68 | { 69 | "serverName": "JobMultiverse", 70 | "functionsPrefix": "job", 71 | "servers": [ 72 | { 73 | "command": "npx", 74 | "args": [ 75 | "-y", 76 | "@benborla29/mcp-server-mysql" 77 | ], 78 | "env": { 79 | "MYSQL_HOST": "127.0.0.1", 80 | "MYSQL_PORT": "3306", 81 | "MYSQL_USER": "root", 82 | "MYSQL_PASS": "", 83 | "MYSQL_DB": "my-job-db" 84 | } 85 | } 86 | ] 87 | } 88 | ~~~ 89 | 90 | Your `side-project-multiverse.json` file 91 | ~~~JSON 92 | { 93 | "serverName": "SideProjectMultiverse", 94 | "functionsPrefix": "side-project", 95 | "servers": [ 96 | { 97 | "command": "npx", 98 | "args": [ 99 | "-y", 100 | "@benborla29/mcp-server-mysql" 101 | ], 102 | "env": { 103 | "MYSQL_HOST": "127.0.0.1", 104 | "MYSQL_PORT": "3306", 105 | "MYSQL_USER": "root", 106 | "MYSQL_PASS": "", 107 | "MYSQL_DB": "side-project-db" 108 | } 109 | } 110 | ] 111 | } 112 | ~~~ 113 | 114 | 115 | ### Create an isolated instance of `mcp-server-filesystem` 116 | 117 | - The `mcp-server-filesystem`'s functions will be exposed with `side-project` prefix, e.g. `side-project_read_file`, `side-project_write_file`. 118 | - The root path can be hidden from the client (e.g. Claude Desktop) by using the `pathResolution` configuration. 119 | 120 | Note that `pathResolution` is optional and is only needed if you want to hide the root path from the client. 121 | 122 | Your `multiverse.json` file 123 | ~~~JSON 124 | { 125 | "serverName": "MySideProject", 126 | "functionsPrefix": "side-project", 127 | "servers": [ 128 | { 129 | "command": "npx", 130 | "args": [ 131 | "-y", 132 | "@modelcontextprotocol/server-filesystem@latest", 133 | "/full/path/to/side-project" 134 | ], 135 | "pathResolution": { 136 | "root": "/full/path/to/side-project", 137 | "applyTo": [ 138 | "path", 139 | "paths" 140 | ] 141 | } 142 | } 143 | ] 144 | } 145 | ~~~ 146 | 147 | 148 | ### Automatic server restart on file changes with `fileWatch` 149 | 150 | Your `multiverse.json` file 151 | ~~~JSON 152 | { 153 | "serverName": "MySideProject", 154 | "functionsPrefix": "side-project", 155 | "servers": [ 156 | { 157 | "command": "node", 158 | "args": [ 159 | "/my-own/mcp-server/i-m-working-on/build/index.js" 160 | ], 161 | "fileWatch": { 162 | "enabled": true, 163 | "path": "/my-own/mcp-server/i-m-working-on/build/" 164 | } 165 | } 166 | ] 167 | } 168 | ~~~ 169 | 170 | ### Hiding specific functions with the `hideFunctions` option 171 | 172 | You can selectively hide specific functions from wrapped servers using the `hideFunctions` array. This is useful when you want to use a server but restrict access to certain potentially dangerous or unnecessary functions. 173 | 174 | The `hideFunctions` array accepts a list of function names that should be hidden from the wrapped server. When a function is hidden: 175 | - It won't be registered with the main MCP server 176 | - It won't be available to the client (e.g., Claude Desktop) 177 | - It won't appear in the list of available functions 178 | 179 | This feature is particularly useful for: 180 | - Restricting access to potentially dangerous functions (e.g., `delete_repository` in GitHub) 181 | - Simplifying the interface by hiding rarely used functions 182 | - Creating different permission levels for different server instances 183 | 184 | ~~~JSON 185 | { 186 | "serverName": "GitHubWithRestrictions", 187 | "functionsPrefix": "github", 188 | "servers": [ 189 | { 190 | "command": "npx", 191 | "args": [ 192 | "-y", 193 | "@modelcontextprotocol/server-github@latest" 194 | ], 195 | "env": { 196 | "GITHUB_PERSONAL_ACCESS_TOKEN": "" 197 | }, 198 | "hideFunctions": [ 199 | "create_repository", 200 | "delete_repository", 201 | "create_issue" 202 | ] 203 | } 204 | ] 205 | } 206 | ~~~ 207 | 208 | In this example, the GitHub server will start normally, but the functions `create_repository`, `delete_repository`, and `create_issue` will be hidden and unavailable to the client. 209 | 210 | 211 | ### Disabling specific servers with the `enabled` flag 212 | 213 | You can selectively disable specific servers in your configuration without removing them from the JSON file by setting the `enabled` flag to `false`. This is useful for temporarily disabling servers during development or testing. 214 | ~~~JSON 215 | { 216 | "serverName": "MySideProject", 217 | "functionsPrefix": "side-project", 218 | "servers": [ 219 | { 220 | "command": "npx", 221 | "args": [ 222 | "-y", 223 | "@modelcontextprotocol/server-filesystem@latest", 224 | "/full/path/to/side-project" 225 | ], 226 | "hideFunctions": [ "write_file" ] 227 | }, 228 | { 229 | "enabled": false, 230 | "command": "npx", 231 | "args": [ 232 | "-y", 233 | "@modelcontextprotocol/server-github@latest" 234 | ] 235 | } 236 | ] 237 | } 238 | ~~~ 239 | 240 | In this example, the first server (filesystem) will start but the function `write_file` has been hidden, the second server (GitHub) is disabled and won't be started. 241 | 242 | ### Full example of a `multiverse.json` file 243 | 244 | This example demonstrates how to create a multiverse server with multiple instances of different server types. 245 | 246 | Note that `pathResolution` is optional and is only needed if you want to hide the root path from the client. 247 | 248 | ~~~JSON 249 | { 250 | "serverName": "HugeProjectWithALotOfResources", 251 | "functionsPrefix": "huge-project", 252 | "servers": [ 253 | { 254 | "command": "node", 255 | "args": [ 256 | "/my-own/mcp-server/i-m-working-on/build/index.js" 257 | ], 258 | "fileWatch": { 259 | "enabled": true, 260 | "path": "/my-own/mcp-server/i-m-working-on/build/" 261 | } 262 | }, 263 | { 264 | "command": "npx", 265 | "args": [ 266 | "-y", 267 | "@modelcontextprotocol/server-filesystem@latest", 268 | "/full/path/to/huge-project" 269 | ], 270 | "pathResolution": { 271 | "root": "/full/path/to/huge-project", 272 | "applyTo": [ 273 | "path", 274 | "paths" 275 | ] 276 | } 277 | }, 278 | { 279 | "command": "npx", 280 | "args": [ 281 | "-y", 282 | "@modelcontextprotocol/server-github@latest" 283 | ], 284 | "env": { 285 | "GITHUB_PERSONAL_ACCESS_TOKEN": "" 286 | } 287 | }, 288 | { 289 | "command": "uvx", 290 | "args": [ 291 | "mcp-server-git", 292 | "--repository", 293 | "/full/path/to/huge-project" 294 | ], 295 | "pathResolution": { 296 | "root": "/full/path/to/huge-project", 297 | "applyTo": [ 298 | "repo_path" 299 | ] 300 | } 301 | } 302 | ] 303 | } 304 | ~~~ 305 | 306 | ## To Do 307 | 308 | - [ ] Add support for `Prompts` 309 | - [ ] Add support for `Resources` 310 | - [ ] Add a GUI for managing multiverse servers 311 | 312 | ## Verified Platforms 313 | 314 | - [x] Windows 315 | - [ ] macOS 316 | - [ ] Linux 317 | 318 | ## License 319 | 320 | MIT 321 | -------------------------------------------------------------------------------- /assets/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamemind/mcp-server-multiverse/d04733a5288b29e6a6b20374639e3c34b6af6a4e/assets/demo.png -------------------------------------------------------------------------------- /dist/inc/json-config.js: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | import * as fs from "node:fs"; 3 | // Schema per la risoluzione dei path 4 | const PathResolutionSchema = z.object({ 5 | root: z.string().describe("Root path for the resolution"), 6 | applyTo: z.array(z.string()).describe("List of keys to apply the resolution to") 7 | }); 8 | // Schema per il file watch 9 | const FileWatchSchema = z.object({ 10 | enabled: z.boolean().describe("Whether the file watch is enabled"), 11 | path: z.string().optional().describe("Path to watch for changes") 12 | }); 13 | // Schema per un singolo server 14 | const ServerSchema = z.object({ 15 | enabled: z.boolean().default(true).describe("Whether this server configuration is enabled"), 16 | command: z.string().describe("Command to run, the same as in 'claude_desktop_config.json'"), 17 | args: z.array(z.string()).describe("Arguments to pass to the command, the same as in 'claude_desktop_config.json'"), 18 | env: z.record(z.string()).optional().describe("Environment variables to set, the same as in 'claude_desktop_config.json'"), 19 | pathResolution: PathResolutionSchema.optional().describe("Relative path resolution configuration"), 20 | fileWatch: FileWatchSchema.optional().describe("File watch configuration"), 21 | hideFunctions: z.array(z.string()).optional().describe("List of function names to hide from this server") 22 | }); 23 | // Schema principale della configurazione 24 | const ConfigSchema = z.object({ 25 | serverName: z.string().describe("Name of the server to expose to the client"), 26 | functionsPrefix: z.string().describe("Aggregation prefix to use for the functions exposed to the client"), 27 | servers: z.array(ServerSchema).describe("List of MCP servers to wrap") 28 | }); 29 | // Funzione di validazione 30 | function validateConfig(config) { 31 | console.error(`Validating configuration...`); 32 | return ConfigSchema.parse(config); 33 | } 34 | function readConfigFile(filePath) { 35 | console.error(`Reading config file from: ${filePath}`); 36 | const jsonContent = fs.readFileSync(filePath, 'utf8'); 37 | const jsonRaw = JSON.parse(jsonContent); 38 | try { 39 | return validateConfig(jsonRaw); 40 | } 41 | catch (error) { 42 | if (error instanceof z.ZodError) { 43 | console.error('Validation errors:', error.errors); 44 | } 45 | throw error; 46 | } 47 | } 48 | export { readConfigFile }; 49 | -------------------------------------------------------------------------------- /dist/inc/main-mcp-server.js: -------------------------------------------------------------------------------- 1 | import { registerWrappedServer } from "./wrapped-servers.js"; 2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 4 | async function startMainServer(config) { 5 | console.error(`Starting main server with name: ${config.serverName}`); 6 | console.error(`Initializing main MCP server...`); 7 | const mainMcpServer = new McpServer({ 8 | name: config.serverName, 9 | version: "1.0.0" 10 | }, { 11 | capabilities: { 12 | prompts: {}, 13 | resources: {} 14 | } 15 | }); 16 | mainMcpServer.prompt(`${config.serverName}_placeholder`, {}, ({}) => ({ 17 | messages: [{ 18 | role: "user", 19 | content: { 20 | type: "text", 21 | text: `this is a placeholder prompt to avoid error logs when no prompts are registered` 22 | } 23 | }] 24 | })); 25 | mainMcpServer.resource(`${config.serverName}_placeholder`, `placeholder://${config.serverName}`, async (uri) => ({ 26 | contents: [{ 27 | uri: uri.href, 28 | text: `This is a placeholder resource to avoid error logs when no resources are registered` 29 | }] 30 | })); 31 | for (const wrappedConfig of config.servers) { 32 | await registerWrappedServer(mainMcpServer, config, wrappedConfig); 33 | } 34 | const transport = new StdioServerTransport(); 35 | await mainMcpServer.connect(transport); 36 | console.error("Server started successfully"); 37 | } 38 | export { startMainServer }; 39 | -------------------------------------------------------------------------------- /dist/inc/main-server.js: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { openWrappedServer } from "./wrapped-servers.js"; 3 | import { convertJsonSchemaToZodShape } from "./zod-utils.js"; 4 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 5 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 6 | async function startMainServer({ prefix, wrappedServerArgs }) { 7 | const thisServer = new McpServer({ 8 | name: prefix, 9 | version: "1.0.0" 10 | }); 11 | thisServer.tool(prefix + `_` + `echo`, "Just a simple echo tool, will be removed in the future", { 12 | input: z.string() 13 | }, async ({ input }) => ({ 14 | content: [{ 15 | type: "text", 16 | text: "you said: " + input 17 | }] 18 | })); 19 | async function registerWrappedServer(thisServer, prefix, wrappedServerArgs) { 20 | const wrappedServer = await openWrappedServer(wrappedServerArgs[0], wrappedServerArgs.slice(1)); 21 | const { tools } = await wrappedServer.listTools(); 22 | tools.forEach((tool) => { 23 | const zodShape = convertJsonSchemaToZodShape(tool.inputSchema); 24 | const prefixedToolName = prefix + `_` + tool.name; 25 | const callback = async (args) => { 26 | const res = await wrappedServer.callTool({ 27 | name: tool.name, 28 | arguments: args 29 | }); 30 | return res; 31 | }; 32 | const description = `[Use this tool only in the "${prefix}" scope] ` + (tool.description || ""); 33 | thisServer.tool(prefixedToolName, description, zodShape, callback); 34 | }); 35 | } 36 | await registerWrappedServer(thisServer, prefix, wrappedServerArgs); 37 | const transport = new StdioServerTransport(); 38 | await thisServer.connect(transport); 39 | console.error("Server started successfully"); 40 | } 41 | -------------------------------------------------------------------------------- /dist/inc/server-arguments.js: -------------------------------------------------------------------------------- 1 | import { program } from "commander"; 2 | export async function parseCliArguments() { 3 | const cliArgs = { 4 | configFile: '', 5 | }; 6 | program 7 | .argument('', 'Json config file') 8 | .action((setupFile) => { 9 | cliArgs.configFile = setupFile; 10 | console.error(`Cli Args ${JSON.stringify(cliArgs)}`); 11 | }); 12 | program.on('error', (err) => { 13 | console.error('Error:', err); 14 | }); 15 | program.parse(process.argv); 16 | return cliArgs; 17 | } 18 | -------------------------------------------------------------------------------- /dist/inc/wrapped-servers.js: -------------------------------------------------------------------------------- 1 | import { Client } from "@modelcontextprotocol/sdk/client/index.js"; 2 | import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; 3 | import { convertJsonSchemaToZodShape } from "./zod-utils.js"; 4 | import path from "node:path"; 5 | import chokidar from 'chokidar'; 6 | async function openWrappedServer(serverConfig) { 7 | console.error(`Opening wrapped server with command: ${serverConfig.command} ${serverConfig.args.join(' ')}`); 8 | const transport = new StdioClientTransport({ 9 | command: serverConfig.command, 10 | args: serverConfig.args, 11 | env: serverConfig.env 12 | }); 13 | const client = new Client({ 14 | name: "wrapper-client", 15 | version: "1.0.0" 16 | }, { 17 | capabilities: { 18 | prompts: {}, 19 | resources: {}, 20 | tools: {} 21 | } 22 | }); 23 | await client.connect(transport); 24 | return client; 25 | } 26 | /** 27 | * Get the tool name to expose from the main server 28 | * @param config 29 | * @param toolName 30 | */ 31 | function getToolName(config, toolName) { 32 | return `${config.functionsPrefix}_${toolName}`; 33 | } 34 | /** 35 | * Apply path resolution to the arguments 36 | * @param args 37 | * @param serverConfig 38 | */ 39 | function applyPathResolution(args, serverConfig) { 40 | serverConfig.pathResolution?.applyTo.forEach((key) => { 41 | if (args[key]) { 42 | const root = serverConfig.pathResolution.root; 43 | const fullPath = path.join(root, args[key]); 44 | console.error(`Rewriting ${key} path ${args[key]} to ${fullPath}`); 45 | args[key] = fullPath; 46 | } 47 | }); 48 | } 49 | /** 50 | * Register tools from the wrapped server 51 | * @param mainMcpServer 52 | * @param mainConfig 53 | * @param wrappedServer 54 | * @param serverConfig 55 | */ 56 | async function registerTools(mainMcpServer, mainConfig, wrappedServer, serverConfig) { 57 | const { tools } = await wrappedServer.listTools(); 58 | tools.forEach((tool) => { 59 | // Skip functions that are in the hideFunctions list 60 | if (serverConfig.hideFunctions && serverConfig.hideFunctions.includes(tool.name)) { 61 | console.error(`Skipping hidden function: ${tool.name}`); 62 | return; 63 | } 64 | const zodShape = convertJsonSchemaToZodShape(tool.inputSchema); 65 | const externalName = getToolName(mainConfig, tool.name); 66 | const callback = async (args) => { 67 | applyPathResolution(args, serverConfig); 68 | const res = await wrappedServer.callTool({ 69 | name: tool.name, 70 | arguments: args 71 | }); 72 | return res; 73 | }; 74 | const description = `[Use this tool only in the "${mainConfig.functionsPrefix}" scope] ` + (tool.description || ""); 75 | mainMcpServer.tool(externalName, description, zodShape, callback); 76 | }); 77 | } 78 | function instantiateFileWatcher(serverConfig, fakeServer) { 79 | console.error(`Setting up file watcher... 80 | enabled: ${serverConfig.fileWatch?.enabled} 81 | path: ${serverConfig.fileWatch?.path}`); 82 | if (serverConfig.fileWatch?.enabled) { 83 | const filepath = serverConfig.fileWatch.path; 84 | chokidar.watch(filepath).on('change', async (file, stats) => { 85 | console.error(`File watcher triggered for: ${file}`); 86 | fakeServer.instanceRebuild++; 87 | console.error(`File ${file} edited - Rebuild #${fakeServer.instanceRebuild}`); 88 | fakeServer.wrappedServerInstance.close(); 89 | fakeServer.wrappedServerInstance = await openWrappedServer(serverConfig); 90 | }); 91 | } 92 | } 93 | async function registerWrappedServer(mainMcpServer, mainConfig, serverConfig) { 94 | // Skip registration if the server is disabled 95 | if (serverConfig.enabled === false) { 96 | console.error(`Skipping disabled server: ${serverConfig.command} ${serverConfig.args.join(' ')}`); 97 | return; 98 | } 99 | console.error(`Registering wrapped server ${serverConfig.command} ${serverConfig.args.join(' ')}`); 100 | /** 101 | * Fake server is used to allow server instance switch if needed by file watch or auto-restart 102 | */ 103 | const fakeServer = { 104 | instanceRebuild: 0, 105 | wrappedServerInstance: await openWrappedServer(serverConfig), 106 | callTool(args) { 107 | return this.wrappedServerInstance.callTool(args); 108 | }, 109 | listTools() { 110 | return this.wrappedServerInstance.listTools(); 111 | } 112 | }; 113 | await registerTools(mainMcpServer, mainConfig, fakeServer, serverConfig); 114 | // TODO register resources 115 | // TODO register prompts 116 | instantiateFileWatcher(serverConfig, fakeServer); 117 | } 118 | export { registerWrappedServer, getToolName }; 119 | -------------------------------------------------------------------------------- /dist/inc/zod-utils.js: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | function convertPropertyToZod(propSchema, isRequired = true) { 3 | let schema; 4 | switch (propSchema.type) { 5 | case 'string': 6 | let stringSchema = z.string(); 7 | if (propSchema.pattern) 8 | stringSchema = stringSchema.regex(new RegExp(propSchema.pattern)); 9 | if (propSchema.minLength) 10 | stringSchema = stringSchema.min(propSchema.minLength); 11 | if (propSchema.maxLength) 12 | stringSchema = stringSchema.max(propSchema.maxLength); 13 | schema = stringSchema; 14 | break; 15 | case 'number': 16 | case 'integer': 17 | let numberSchema = propSchema.type === 'integer' ? z.number().int() : z.number(); 18 | if (propSchema.minimum !== undefined) 19 | numberSchema = numberSchema.min(propSchema.minimum); 20 | if (propSchema.maximum !== undefined) 21 | numberSchema = numberSchema.max(propSchema.maximum); 22 | schema = numberSchema; 23 | break; 24 | case 'boolean': 25 | schema = z.boolean(); 26 | break; 27 | case 'array': 28 | const itemSchema = propSchema.items ? convertPropertyToZod(propSchema.items) : z.any(); 29 | schema = z.array(itemSchema); 30 | break; 31 | case 'object': 32 | schema = z.object(jsonPropsToZodShape(propSchema.properties, propSchema.required || [])); 33 | break; 34 | default: 35 | schema = z.any(); 36 | } 37 | if (propSchema.description) 38 | schema = schema.describe(propSchema.description); 39 | return isRequired ? schema : schema.optional(); 40 | } 41 | function jsonPropsToZodShape(properties, required = []) { 42 | const shape = {}; 43 | if (properties && typeof properties === 'object') 44 | for (const [key, propSchema] of Object.entries(properties)) { 45 | const isRequired = required.includes(key); 46 | shape[key] = convertPropertyToZod(propSchema, isRequired); 47 | } 48 | return shape; 49 | } 50 | function convertJsonSchemaToZodShape(schema) { 51 | if (schema.type !== 'object' || !schema.properties) { 52 | throw new Error('Schema must be an object type with properties'); 53 | } 54 | return jsonPropsToZodShape(schema.properties, schema.required || []); 55 | } 56 | export { convertJsonSchemaToZodShape }; 57 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { parseCliArguments } from "./inc/server-arguments.js"; 3 | import { readConfigFile } from "./inc/json-config.js"; 4 | import { startMainServer } from "./inc/main-mcp-server.js"; 5 | (async function () { 6 | console.error(`Starting MCP Server Wrapper...`); 7 | const cliArguments = await parseCliArguments(); 8 | const wrapperConfig = readConfigFile(cliArguments.configFile); 9 | console.error(wrapperConfig); 10 | await startMainServer(wrapperConfig); 11 | })(); 12 | -------------------------------------------------------------------------------- /dist/server-arguments.js: -------------------------------------------------------------------------------- 1 | import {program} from "commander"; 2 | 3 | export async function parseCliArguments() { 4 | const cliArgs = { 5 | wrappedServer: '', 6 | prefix: '', 7 | watch: false 8 | }; 9 | program 10 | .argument('', 'Prefix') 11 | .argument('', 'Wrapped Server') 12 | .option('-w, --watch', 'Watch for changes and restart the server') 13 | .action((prefix, wrappedServer, options) => { 14 | cliArgs.prefix = prefix; 15 | cliArgs.wrappedServer = wrappedServer; 16 | cliArgs.watch = options.watch; 17 | console.error(`Cli Args ${JSON.stringify(cliArgs)}`); 18 | }); 19 | // Aggiungiamo un handler per gli errori 20 | program.on('error', (err) => { 21 | console.error('Error:', err); 22 | }); 23 | program.parse(process.argv); 24 | return cliArgs; 25 | } 26 | 27 | export async function parseCliArguments2() { 28 | const cliArgs = { 29 | setupFile: '', 30 | }; 31 | 32 | program 33 | .argument('', 'Json setup file') 34 | .action((setupFile) => { 35 | cliArgs.setupFile = setupFile; 36 | console.error(`Cli Args ${JSON.stringify(cliArgs)}`); 37 | }); 38 | 39 | program.on('error', (err) => { 40 | console.error('Error:', err); 41 | }); 42 | 43 | program.parse(process.argv); 44 | return cliArgs; 45 | } 46 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lamemind/mcp-server-multiverse", 3 | "version": "1.1.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@lamemind/mcp-server-multiverse", 9 | "version": "1.1.1", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@modelcontextprotocol/sdk": "^1.12.0", 13 | "chokidar": "^4.0.3", 14 | "commander": "^13.1.0", 15 | "zod-to-json-schema": "^3.24.3" 16 | }, 17 | "bin": { 18 | "mcp-server-multiverse": "dist/index.js" 19 | }, 20 | "devDependencies": { 21 | "@types/express": "^5.0.0", 22 | "@types/node": "^22.13.5", 23 | "shx": "^0.3.4", 24 | "tsx": "^4.19.3", 25 | "typescript": "^5.7.3" 26 | } 27 | }, 28 | "node_modules/@esbuild/aix-ppc64": { 29 | "version": "0.25.4", 30 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", 31 | "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", 32 | "cpu": [ 33 | "ppc64" 34 | ], 35 | "dev": true, 36 | "license": "MIT", 37 | "optional": true, 38 | "os": [ 39 | "aix" 40 | ], 41 | "engines": { 42 | "node": ">=18" 43 | } 44 | }, 45 | "node_modules/@esbuild/android-arm": { 46 | "version": "0.25.4", 47 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", 48 | "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", 49 | "cpu": [ 50 | "arm" 51 | ], 52 | "dev": true, 53 | "license": "MIT", 54 | "optional": true, 55 | "os": [ 56 | "android" 57 | ], 58 | "engines": { 59 | "node": ">=18" 60 | } 61 | }, 62 | "node_modules/@esbuild/android-arm64": { 63 | "version": "0.25.4", 64 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", 65 | "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", 66 | "cpu": [ 67 | "arm64" 68 | ], 69 | "dev": true, 70 | "license": "MIT", 71 | "optional": true, 72 | "os": [ 73 | "android" 74 | ], 75 | "engines": { 76 | "node": ">=18" 77 | } 78 | }, 79 | "node_modules/@esbuild/android-x64": { 80 | "version": "0.25.4", 81 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", 82 | "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", 83 | "cpu": [ 84 | "x64" 85 | ], 86 | "dev": true, 87 | "license": "MIT", 88 | "optional": true, 89 | "os": [ 90 | "android" 91 | ], 92 | "engines": { 93 | "node": ">=18" 94 | } 95 | }, 96 | "node_modules/@esbuild/darwin-arm64": { 97 | "version": "0.25.4", 98 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", 99 | "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", 100 | "cpu": [ 101 | "arm64" 102 | ], 103 | "dev": true, 104 | "license": "MIT", 105 | "optional": true, 106 | "os": [ 107 | "darwin" 108 | ], 109 | "engines": { 110 | "node": ">=18" 111 | } 112 | }, 113 | "node_modules/@esbuild/darwin-x64": { 114 | "version": "0.25.4", 115 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", 116 | "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", 117 | "cpu": [ 118 | "x64" 119 | ], 120 | "dev": true, 121 | "license": "MIT", 122 | "optional": true, 123 | "os": [ 124 | "darwin" 125 | ], 126 | "engines": { 127 | "node": ">=18" 128 | } 129 | }, 130 | "node_modules/@esbuild/freebsd-arm64": { 131 | "version": "0.25.4", 132 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", 133 | "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", 134 | "cpu": [ 135 | "arm64" 136 | ], 137 | "dev": true, 138 | "license": "MIT", 139 | "optional": true, 140 | "os": [ 141 | "freebsd" 142 | ], 143 | "engines": { 144 | "node": ">=18" 145 | } 146 | }, 147 | "node_modules/@esbuild/freebsd-x64": { 148 | "version": "0.25.4", 149 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", 150 | "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", 151 | "cpu": [ 152 | "x64" 153 | ], 154 | "dev": true, 155 | "license": "MIT", 156 | "optional": true, 157 | "os": [ 158 | "freebsd" 159 | ], 160 | "engines": { 161 | "node": ">=18" 162 | } 163 | }, 164 | "node_modules/@esbuild/linux-arm": { 165 | "version": "0.25.4", 166 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", 167 | "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", 168 | "cpu": [ 169 | "arm" 170 | ], 171 | "dev": true, 172 | "license": "MIT", 173 | "optional": true, 174 | "os": [ 175 | "linux" 176 | ], 177 | "engines": { 178 | "node": ">=18" 179 | } 180 | }, 181 | "node_modules/@esbuild/linux-arm64": { 182 | "version": "0.25.4", 183 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", 184 | "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", 185 | "cpu": [ 186 | "arm64" 187 | ], 188 | "dev": true, 189 | "license": "MIT", 190 | "optional": true, 191 | "os": [ 192 | "linux" 193 | ], 194 | "engines": { 195 | "node": ">=18" 196 | } 197 | }, 198 | "node_modules/@esbuild/linux-ia32": { 199 | "version": "0.25.4", 200 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", 201 | "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", 202 | "cpu": [ 203 | "ia32" 204 | ], 205 | "dev": true, 206 | "license": "MIT", 207 | "optional": true, 208 | "os": [ 209 | "linux" 210 | ], 211 | "engines": { 212 | "node": ">=18" 213 | } 214 | }, 215 | "node_modules/@esbuild/linux-loong64": { 216 | "version": "0.25.4", 217 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", 218 | "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", 219 | "cpu": [ 220 | "loong64" 221 | ], 222 | "dev": true, 223 | "license": "MIT", 224 | "optional": true, 225 | "os": [ 226 | "linux" 227 | ], 228 | "engines": { 229 | "node": ">=18" 230 | } 231 | }, 232 | "node_modules/@esbuild/linux-mips64el": { 233 | "version": "0.25.4", 234 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", 235 | "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", 236 | "cpu": [ 237 | "mips64el" 238 | ], 239 | "dev": true, 240 | "license": "MIT", 241 | "optional": true, 242 | "os": [ 243 | "linux" 244 | ], 245 | "engines": { 246 | "node": ">=18" 247 | } 248 | }, 249 | "node_modules/@esbuild/linux-ppc64": { 250 | "version": "0.25.4", 251 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", 252 | "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", 253 | "cpu": [ 254 | "ppc64" 255 | ], 256 | "dev": true, 257 | "license": "MIT", 258 | "optional": true, 259 | "os": [ 260 | "linux" 261 | ], 262 | "engines": { 263 | "node": ">=18" 264 | } 265 | }, 266 | "node_modules/@esbuild/linux-riscv64": { 267 | "version": "0.25.4", 268 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", 269 | "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", 270 | "cpu": [ 271 | "riscv64" 272 | ], 273 | "dev": true, 274 | "license": "MIT", 275 | "optional": true, 276 | "os": [ 277 | "linux" 278 | ], 279 | "engines": { 280 | "node": ">=18" 281 | } 282 | }, 283 | "node_modules/@esbuild/linux-s390x": { 284 | "version": "0.25.4", 285 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", 286 | "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", 287 | "cpu": [ 288 | "s390x" 289 | ], 290 | "dev": true, 291 | "license": "MIT", 292 | "optional": true, 293 | "os": [ 294 | "linux" 295 | ], 296 | "engines": { 297 | "node": ">=18" 298 | } 299 | }, 300 | "node_modules/@esbuild/linux-x64": { 301 | "version": "0.25.4", 302 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", 303 | "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", 304 | "cpu": [ 305 | "x64" 306 | ], 307 | "dev": true, 308 | "license": "MIT", 309 | "optional": true, 310 | "os": [ 311 | "linux" 312 | ], 313 | "engines": { 314 | "node": ">=18" 315 | } 316 | }, 317 | "node_modules/@esbuild/netbsd-arm64": { 318 | "version": "0.25.4", 319 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", 320 | "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", 321 | "cpu": [ 322 | "arm64" 323 | ], 324 | "dev": true, 325 | "license": "MIT", 326 | "optional": true, 327 | "os": [ 328 | "netbsd" 329 | ], 330 | "engines": { 331 | "node": ">=18" 332 | } 333 | }, 334 | "node_modules/@esbuild/netbsd-x64": { 335 | "version": "0.25.4", 336 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", 337 | "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", 338 | "cpu": [ 339 | "x64" 340 | ], 341 | "dev": true, 342 | "license": "MIT", 343 | "optional": true, 344 | "os": [ 345 | "netbsd" 346 | ], 347 | "engines": { 348 | "node": ">=18" 349 | } 350 | }, 351 | "node_modules/@esbuild/openbsd-arm64": { 352 | "version": "0.25.4", 353 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", 354 | "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", 355 | "cpu": [ 356 | "arm64" 357 | ], 358 | "dev": true, 359 | "license": "MIT", 360 | "optional": true, 361 | "os": [ 362 | "openbsd" 363 | ], 364 | "engines": { 365 | "node": ">=18" 366 | } 367 | }, 368 | "node_modules/@esbuild/openbsd-x64": { 369 | "version": "0.25.4", 370 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", 371 | "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", 372 | "cpu": [ 373 | "x64" 374 | ], 375 | "dev": true, 376 | "license": "MIT", 377 | "optional": true, 378 | "os": [ 379 | "openbsd" 380 | ], 381 | "engines": { 382 | "node": ">=18" 383 | } 384 | }, 385 | "node_modules/@esbuild/sunos-x64": { 386 | "version": "0.25.4", 387 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", 388 | "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", 389 | "cpu": [ 390 | "x64" 391 | ], 392 | "dev": true, 393 | "license": "MIT", 394 | "optional": true, 395 | "os": [ 396 | "sunos" 397 | ], 398 | "engines": { 399 | "node": ">=18" 400 | } 401 | }, 402 | "node_modules/@esbuild/win32-arm64": { 403 | "version": "0.25.4", 404 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", 405 | "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", 406 | "cpu": [ 407 | "arm64" 408 | ], 409 | "dev": true, 410 | "license": "MIT", 411 | "optional": true, 412 | "os": [ 413 | "win32" 414 | ], 415 | "engines": { 416 | "node": ">=18" 417 | } 418 | }, 419 | "node_modules/@esbuild/win32-ia32": { 420 | "version": "0.25.4", 421 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", 422 | "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", 423 | "cpu": [ 424 | "ia32" 425 | ], 426 | "dev": true, 427 | "license": "MIT", 428 | "optional": true, 429 | "os": [ 430 | "win32" 431 | ], 432 | "engines": { 433 | "node": ">=18" 434 | } 435 | }, 436 | "node_modules/@esbuild/win32-x64": { 437 | "version": "0.25.4", 438 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", 439 | "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", 440 | "cpu": [ 441 | "x64" 442 | ], 443 | "dev": true, 444 | "license": "MIT", 445 | "optional": true, 446 | "os": [ 447 | "win32" 448 | ], 449 | "engines": { 450 | "node": ">=18" 451 | } 452 | }, 453 | "node_modules/@modelcontextprotocol/sdk": { 454 | "version": "1.12.0", 455 | "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.0.tgz", 456 | "integrity": "sha512-m//7RlINx1F3sz3KqwY1WWzVgTcYX52HYk4bJ1hkBXV3zccAEth+jRvG8DBRrdaQuRsPAJOx2MH3zaHNCKL7Zg==", 457 | "license": "MIT", 458 | "dependencies": { 459 | "ajv": "^6.12.6", 460 | "content-type": "^1.0.5", 461 | "cors": "^2.8.5", 462 | "cross-spawn": "^7.0.5", 463 | "eventsource": "^3.0.2", 464 | "express": "^5.0.1", 465 | "express-rate-limit": "^7.5.0", 466 | "pkce-challenge": "^5.0.0", 467 | "raw-body": "^3.0.0", 468 | "zod": "^3.23.8", 469 | "zod-to-json-schema": "^3.24.1" 470 | }, 471 | "engines": { 472 | "node": ">=18" 473 | } 474 | }, 475 | "node_modules/@types/body-parser": { 476 | "version": "1.19.5", 477 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", 478 | "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", 479 | "dev": true, 480 | "license": "MIT", 481 | "dependencies": { 482 | "@types/connect": "*", 483 | "@types/node": "*" 484 | } 485 | }, 486 | "node_modules/@types/connect": { 487 | "version": "3.4.38", 488 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", 489 | "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", 490 | "dev": true, 491 | "license": "MIT", 492 | "dependencies": { 493 | "@types/node": "*" 494 | } 495 | }, 496 | "node_modules/@types/express": { 497 | "version": "5.0.2", 498 | "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.2.tgz", 499 | "integrity": "sha512-BtjL3ZwbCQriyb0DGw+Rt12qAXPiBTPs815lsUvtt1Grk0vLRMZNMUZ741d5rjk+UQOxfDiBZ3dxpX00vSkK3g==", 500 | "dev": true, 501 | "license": "MIT", 502 | "dependencies": { 503 | "@types/body-parser": "*", 504 | "@types/express-serve-static-core": "^5.0.0", 505 | "@types/serve-static": "*" 506 | } 507 | }, 508 | "node_modules/@types/express-serve-static-core": { 509 | "version": "5.0.6", 510 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", 511 | "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", 512 | "dev": true, 513 | "license": "MIT", 514 | "dependencies": { 515 | "@types/node": "*", 516 | "@types/qs": "*", 517 | "@types/range-parser": "*", 518 | "@types/send": "*" 519 | } 520 | }, 521 | "node_modules/@types/http-errors": { 522 | "version": "2.0.4", 523 | "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", 524 | "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", 525 | "dev": true, 526 | "license": "MIT" 527 | }, 528 | "node_modules/@types/mime": { 529 | "version": "1.3.5", 530 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", 531 | "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", 532 | "dev": true, 533 | "license": "MIT" 534 | }, 535 | "node_modules/@types/node": { 536 | "version": "22.15.21", 537 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz", 538 | "integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==", 539 | "dev": true, 540 | "license": "MIT", 541 | "dependencies": { 542 | "undici-types": "~6.21.0" 543 | } 544 | }, 545 | "node_modules/@types/qs": { 546 | "version": "6.14.0", 547 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", 548 | "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", 549 | "dev": true, 550 | "license": "MIT" 551 | }, 552 | "node_modules/@types/range-parser": { 553 | "version": "1.2.7", 554 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", 555 | "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", 556 | "dev": true, 557 | "license": "MIT" 558 | }, 559 | "node_modules/@types/send": { 560 | "version": "0.17.4", 561 | "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", 562 | "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", 563 | "dev": true, 564 | "license": "MIT", 565 | "dependencies": { 566 | "@types/mime": "^1", 567 | "@types/node": "*" 568 | } 569 | }, 570 | "node_modules/@types/serve-static": { 571 | "version": "1.15.7", 572 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", 573 | "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", 574 | "dev": true, 575 | "license": "MIT", 576 | "dependencies": { 577 | "@types/http-errors": "*", 578 | "@types/node": "*", 579 | "@types/send": "*" 580 | } 581 | }, 582 | "node_modules/accepts": { 583 | "version": "2.0.0", 584 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", 585 | "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", 586 | "license": "MIT", 587 | "dependencies": { 588 | "mime-types": "^3.0.0", 589 | "negotiator": "^1.0.0" 590 | }, 591 | "engines": { 592 | "node": ">= 0.6" 593 | } 594 | }, 595 | "node_modules/ajv": { 596 | "version": "6.12.6", 597 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 598 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 599 | "license": "MIT", 600 | "dependencies": { 601 | "fast-deep-equal": "^3.1.1", 602 | "fast-json-stable-stringify": "^2.0.0", 603 | "json-schema-traverse": "^0.4.1", 604 | "uri-js": "^4.2.2" 605 | }, 606 | "funding": { 607 | "type": "github", 608 | "url": "https://github.com/sponsors/epoberezkin" 609 | } 610 | }, 611 | "node_modules/balanced-match": { 612 | "version": "1.0.2", 613 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 614 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 615 | "dev": true, 616 | "license": "MIT" 617 | }, 618 | "node_modules/body-parser": { 619 | "version": "2.2.0", 620 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", 621 | "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", 622 | "license": "MIT", 623 | "dependencies": { 624 | "bytes": "^3.1.2", 625 | "content-type": "^1.0.5", 626 | "debug": "^4.4.0", 627 | "http-errors": "^2.0.0", 628 | "iconv-lite": "^0.6.3", 629 | "on-finished": "^2.4.1", 630 | "qs": "^6.14.0", 631 | "raw-body": "^3.0.0", 632 | "type-is": "^2.0.0" 633 | }, 634 | "engines": { 635 | "node": ">=18" 636 | } 637 | }, 638 | "node_modules/brace-expansion": { 639 | "version": "1.1.11", 640 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 641 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 642 | "dev": true, 643 | "license": "MIT", 644 | "dependencies": { 645 | "balanced-match": "^1.0.0", 646 | "concat-map": "0.0.1" 647 | } 648 | }, 649 | "node_modules/bytes": { 650 | "version": "3.1.2", 651 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 652 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 653 | "license": "MIT", 654 | "engines": { 655 | "node": ">= 0.8" 656 | } 657 | }, 658 | "node_modules/call-bind-apply-helpers": { 659 | "version": "1.0.2", 660 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", 661 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", 662 | "license": "MIT", 663 | "dependencies": { 664 | "es-errors": "^1.3.0", 665 | "function-bind": "^1.1.2" 666 | }, 667 | "engines": { 668 | "node": ">= 0.4" 669 | } 670 | }, 671 | "node_modules/call-bound": { 672 | "version": "1.0.4", 673 | "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", 674 | "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", 675 | "license": "MIT", 676 | "dependencies": { 677 | "call-bind-apply-helpers": "^1.0.2", 678 | "get-intrinsic": "^1.3.0" 679 | }, 680 | "engines": { 681 | "node": ">= 0.4" 682 | }, 683 | "funding": { 684 | "url": "https://github.com/sponsors/ljharb" 685 | } 686 | }, 687 | "node_modules/chokidar": { 688 | "version": "4.0.3", 689 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", 690 | "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", 691 | "license": "MIT", 692 | "dependencies": { 693 | "readdirp": "^4.0.1" 694 | }, 695 | "engines": { 696 | "node": ">= 14.16.0" 697 | }, 698 | "funding": { 699 | "url": "https://paulmillr.com/funding/" 700 | } 701 | }, 702 | "node_modules/commander": { 703 | "version": "13.1.0", 704 | "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", 705 | "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", 706 | "license": "MIT", 707 | "engines": { 708 | "node": ">=18" 709 | } 710 | }, 711 | "node_modules/concat-map": { 712 | "version": "0.0.1", 713 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 714 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 715 | "dev": true, 716 | "license": "MIT" 717 | }, 718 | "node_modules/content-disposition": { 719 | "version": "1.0.0", 720 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", 721 | "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", 722 | "license": "MIT", 723 | "dependencies": { 724 | "safe-buffer": "5.2.1" 725 | }, 726 | "engines": { 727 | "node": ">= 0.6" 728 | } 729 | }, 730 | "node_modules/content-type": { 731 | "version": "1.0.5", 732 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 733 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 734 | "license": "MIT", 735 | "engines": { 736 | "node": ">= 0.6" 737 | } 738 | }, 739 | "node_modules/cookie": { 740 | "version": "0.7.2", 741 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", 742 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", 743 | "license": "MIT", 744 | "engines": { 745 | "node": ">= 0.6" 746 | } 747 | }, 748 | "node_modules/cookie-signature": { 749 | "version": "1.2.2", 750 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", 751 | "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", 752 | "license": "MIT", 753 | "engines": { 754 | "node": ">=6.6.0" 755 | } 756 | }, 757 | "node_modules/cors": { 758 | "version": "2.8.5", 759 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 760 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 761 | "license": "MIT", 762 | "dependencies": { 763 | "object-assign": "^4", 764 | "vary": "^1" 765 | }, 766 | "engines": { 767 | "node": ">= 0.10" 768 | } 769 | }, 770 | "node_modules/cross-spawn": { 771 | "version": "7.0.6", 772 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 773 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 774 | "license": "MIT", 775 | "dependencies": { 776 | "path-key": "^3.1.0", 777 | "shebang-command": "^2.0.0", 778 | "which": "^2.0.1" 779 | }, 780 | "engines": { 781 | "node": ">= 8" 782 | } 783 | }, 784 | "node_modules/debug": { 785 | "version": "4.4.1", 786 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", 787 | "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", 788 | "license": "MIT", 789 | "dependencies": { 790 | "ms": "^2.1.3" 791 | }, 792 | "engines": { 793 | "node": ">=6.0" 794 | }, 795 | "peerDependenciesMeta": { 796 | "supports-color": { 797 | "optional": true 798 | } 799 | } 800 | }, 801 | "node_modules/depd": { 802 | "version": "2.0.0", 803 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 804 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 805 | "license": "MIT", 806 | "engines": { 807 | "node": ">= 0.8" 808 | } 809 | }, 810 | "node_modules/dunder-proto": { 811 | "version": "1.0.1", 812 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", 813 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", 814 | "license": "MIT", 815 | "dependencies": { 816 | "call-bind-apply-helpers": "^1.0.1", 817 | "es-errors": "^1.3.0", 818 | "gopd": "^1.2.0" 819 | }, 820 | "engines": { 821 | "node": ">= 0.4" 822 | } 823 | }, 824 | "node_modules/ee-first": { 825 | "version": "1.1.1", 826 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 827 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", 828 | "license": "MIT" 829 | }, 830 | "node_modules/encodeurl": { 831 | "version": "2.0.0", 832 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 833 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 834 | "license": "MIT", 835 | "engines": { 836 | "node": ">= 0.8" 837 | } 838 | }, 839 | "node_modules/es-define-property": { 840 | "version": "1.0.1", 841 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", 842 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", 843 | "license": "MIT", 844 | "engines": { 845 | "node": ">= 0.4" 846 | } 847 | }, 848 | "node_modules/es-errors": { 849 | "version": "1.3.0", 850 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 851 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 852 | "license": "MIT", 853 | "engines": { 854 | "node": ">= 0.4" 855 | } 856 | }, 857 | "node_modules/es-object-atoms": { 858 | "version": "1.1.1", 859 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", 860 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", 861 | "license": "MIT", 862 | "dependencies": { 863 | "es-errors": "^1.3.0" 864 | }, 865 | "engines": { 866 | "node": ">= 0.4" 867 | } 868 | }, 869 | "node_modules/esbuild": { 870 | "version": "0.25.4", 871 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", 872 | "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", 873 | "dev": true, 874 | "hasInstallScript": true, 875 | "license": "MIT", 876 | "bin": { 877 | "esbuild": "bin/esbuild" 878 | }, 879 | "engines": { 880 | "node": ">=18" 881 | }, 882 | "optionalDependencies": { 883 | "@esbuild/aix-ppc64": "0.25.4", 884 | "@esbuild/android-arm": "0.25.4", 885 | "@esbuild/android-arm64": "0.25.4", 886 | "@esbuild/android-x64": "0.25.4", 887 | "@esbuild/darwin-arm64": "0.25.4", 888 | "@esbuild/darwin-x64": "0.25.4", 889 | "@esbuild/freebsd-arm64": "0.25.4", 890 | "@esbuild/freebsd-x64": "0.25.4", 891 | "@esbuild/linux-arm": "0.25.4", 892 | "@esbuild/linux-arm64": "0.25.4", 893 | "@esbuild/linux-ia32": "0.25.4", 894 | "@esbuild/linux-loong64": "0.25.4", 895 | "@esbuild/linux-mips64el": "0.25.4", 896 | "@esbuild/linux-ppc64": "0.25.4", 897 | "@esbuild/linux-riscv64": "0.25.4", 898 | "@esbuild/linux-s390x": "0.25.4", 899 | "@esbuild/linux-x64": "0.25.4", 900 | "@esbuild/netbsd-arm64": "0.25.4", 901 | "@esbuild/netbsd-x64": "0.25.4", 902 | "@esbuild/openbsd-arm64": "0.25.4", 903 | "@esbuild/openbsd-x64": "0.25.4", 904 | "@esbuild/sunos-x64": "0.25.4", 905 | "@esbuild/win32-arm64": "0.25.4", 906 | "@esbuild/win32-ia32": "0.25.4", 907 | "@esbuild/win32-x64": "0.25.4" 908 | } 909 | }, 910 | "node_modules/escape-html": { 911 | "version": "1.0.3", 912 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 913 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", 914 | "license": "MIT" 915 | }, 916 | "node_modules/etag": { 917 | "version": "1.8.1", 918 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 919 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 920 | "license": "MIT", 921 | "engines": { 922 | "node": ">= 0.6" 923 | } 924 | }, 925 | "node_modules/eventsource": { 926 | "version": "3.0.7", 927 | "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", 928 | "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", 929 | "license": "MIT", 930 | "dependencies": { 931 | "eventsource-parser": "^3.0.1" 932 | }, 933 | "engines": { 934 | "node": ">=18.0.0" 935 | } 936 | }, 937 | "node_modules/eventsource-parser": { 938 | "version": "3.0.2", 939 | "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.2.tgz", 940 | "integrity": "sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==", 941 | "license": "MIT", 942 | "engines": { 943 | "node": ">=18.0.0" 944 | } 945 | }, 946 | "node_modules/express": { 947 | "version": "5.1.0", 948 | "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", 949 | "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", 950 | "license": "MIT", 951 | "dependencies": { 952 | "accepts": "^2.0.0", 953 | "body-parser": "^2.2.0", 954 | "content-disposition": "^1.0.0", 955 | "content-type": "^1.0.5", 956 | "cookie": "^0.7.1", 957 | "cookie-signature": "^1.2.1", 958 | "debug": "^4.4.0", 959 | "encodeurl": "^2.0.0", 960 | "escape-html": "^1.0.3", 961 | "etag": "^1.8.1", 962 | "finalhandler": "^2.1.0", 963 | "fresh": "^2.0.0", 964 | "http-errors": "^2.0.0", 965 | "merge-descriptors": "^2.0.0", 966 | "mime-types": "^3.0.0", 967 | "on-finished": "^2.4.1", 968 | "once": "^1.4.0", 969 | "parseurl": "^1.3.3", 970 | "proxy-addr": "^2.0.7", 971 | "qs": "^6.14.0", 972 | "range-parser": "^1.2.1", 973 | "router": "^2.2.0", 974 | "send": "^1.1.0", 975 | "serve-static": "^2.2.0", 976 | "statuses": "^2.0.1", 977 | "type-is": "^2.0.1", 978 | "vary": "^1.1.2" 979 | }, 980 | "engines": { 981 | "node": ">= 18" 982 | }, 983 | "funding": { 984 | "type": "opencollective", 985 | "url": "https://opencollective.com/express" 986 | } 987 | }, 988 | "node_modules/express-rate-limit": { 989 | "version": "7.5.0", 990 | "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", 991 | "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", 992 | "license": "MIT", 993 | "engines": { 994 | "node": ">= 16" 995 | }, 996 | "funding": { 997 | "url": "https://github.com/sponsors/express-rate-limit" 998 | }, 999 | "peerDependencies": { 1000 | "express": "^4.11 || 5 || ^5.0.0-beta.1" 1001 | } 1002 | }, 1003 | "node_modules/fast-deep-equal": { 1004 | "version": "3.1.3", 1005 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1006 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1007 | "license": "MIT" 1008 | }, 1009 | "node_modules/fast-json-stable-stringify": { 1010 | "version": "2.1.0", 1011 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1012 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1013 | "license": "MIT" 1014 | }, 1015 | "node_modules/finalhandler": { 1016 | "version": "2.1.0", 1017 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", 1018 | "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", 1019 | "license": "MIT", 1020 | "dependencies": { 1021 | "debug": "^4.4.0", 1022 | "encodeurl": "^2.0.0", 1023 | "escape-html": "^1.0.3", 1024 | "on-finished": "^2.4.1", 1025 | "parseurl": "^1.3.3", 1026 | "statuses": "^2.0.1" 1027 | }, 1028 | "engines": { 1029 | "node": ">= 0.8" 1030 | } 1031 | }, 1032 | "node_modules/forwarded": { 1033 | "version": "0.2.0", 1034 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 1035 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 1036 | "license": "MIT", 1037 | "engines": { 1038 | "node": ">= 0.6" 1039 | } 1040 | }, 1041 | "node_modules/fresh": { 1042 | "version": "2.0.0", 1043 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", 1044 | "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", 1045 | "license": "MIT", 1046 | "engines": { 1047 | "node": ">= 0.8" 1048 | } 1049 | }, 1050 | "node_modules/fs.realpath": { 1051 | "version": "1.0.0", 1052 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1053 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1054 | "dev": true, 1055 | "license": "ISC" 1056 | }, 1057 | "node_modules/fsevents": { 1058 | "version": "2.3.3", 1059 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1060 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1061 | "dev": true, 1062 | "hasInstallScript": true, 1063 | "license": "MIT", 1064 | "optional": true, 1065 | "os": [ 1066 | "darwin" 1067 | ], 1068 | "engines": { 1069 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1070 | } 1071 | }, 1072 | "node_modules/function-bind": { 1073 | "version": "1.1.2", 1074 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 1075 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 1076 | "license": "MIT", 1077 | "funding": { 1078 | "url": "https://github.com/sponsors/ljharb" 1079 | } 1080 | }, 1081 | "node_modules/get-intrinsic": { 1082 | "version": "1.3.0", 1083 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", 1084 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", 1085 | "license": "MIT", 1086 | "dependencies": { 1087 | "call-bind-apply-helpers": "^1.0.2", 1088 | "es-define-property": "^1.0.1", 1089 | "es-errors": "^1.3.0", 1090 | "es-object-atoms": "^1.1.1", 1091 | "function-bind": "^1.1.2", 1092 | "get-proto": "^1.0.1", 1093 | "gopd": "^1.2.0", 1094 | "has-symbols": "^1.1.0", 1095 | "hasown": "^2.0.2", 1096 | "math-intrinsics": "^1.1.0" 1097 | }, 1098 | "engines": { 1099 | "node": ">= 0.4" 1100 | }, 1101 | "funding": { 1102 | "url": "https://github.com/sponsors/ljharb" 1103 | } 1104 | }, 1105 | "node_modules/get-proto": { 1106 | "version": "1.0.1", 1107 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", 1108 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", 1109 | "license": "MIT", 1110 | "dependencies": { 1111 | "dunder-proto": "^1.0.1", 1112 | "es-object-atoms": "^1.0.0" 1113 | }, 1114 | "engines": { 1115 | "node": ">= 0.4" 1116 | } 1117 | }, 1118 | "node_modules/get-tsconfig": { 1119 | "version": "4.10.1", 1120 | "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", 1121 | "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", 1122 | "dev": true, 1123 | "license": "MIT", 1124 | "dependencies": { 1125 | "resolve-pkg-maps": "^1.0.0" 1126 | }, 1127 | "funding": { 1128 | "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 1129 | } 1130 | }, 1131 | "node_modules/glob": { 1132 | "version": "7.2.3", 1133 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 1134 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 1135 | "deprecated": "Glob versions prior to v9 are no longer supported", 1136 | "dev": true, 1137 | "license": "ISC", 1138 | "dependencies": { 1139 | "fs.realpath": "^1.0.0", 1140 | "inflight": "^1.0.4", 1141 | "inherits": "2", 1142 | "minimatch": "^3.1.1", 1143 | "once": "^1.3.0", 1144 | "path-is-absolute": "^1.0.0" 1145 | }, 1146 | "engines": { 1147 | "node": "*" 1148 | }, 1149 | "funding": { 1150 | "url": "https://github.com/sponsors/isaacs" 1151 | } 1152 | }, 1153 | "node_modules/gopd": { 1154 | "version": "1.2.0", 1155 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", 1156 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", 1157 | "license": "MIT", 1158 | "engines": { 1159 | "node": ">= 0.4" 1160 | }, 1161 | "funding": { 1162 | "url": "https://github.com/sponsors/ljharb" 1163 | } 1164 | }, 1165 | "node_modules/has-symbols": { 1166 | "version": "1.1.0", 1167 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", 1168 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", 1169 | "license": "MIT", 1170 | "engines": { 1171 | "node": ">= 0.4" 1172 | }, 1173 | "funding": { 1174 | "url": "https://github.com/sponsors/ljharb" 1175 | } 1176 | }, 1177 | "node_modules/hasown": { 1178 | "version": "2.0.2", 1179 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 1180 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 1181 | "license": "MIT", 1182 | "dependencies": { 1183 | "function-bind": "^1.1.2" 1184 | }, 1185 | "engines": { 1186 | "node": ">= 0.4" 1187 | } 1188 | }, 1189 | "node_modules/http-errors": { 1190 | "version": "2.0.0", 1191 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 1192 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 1193 | "license": "MIT", 1194 | "dependencies": { 1195 | "depd": "2.0.0", 1196 | "inherits": "2.0.4", 1197 | "setprototypeof": "1.2.0", 1198 | "statuses": "2.0.1", 1199 | "toidentifier": "1.0.1" 1200 | }, 1201 | "engines": { 1202 | "node": ">= 0.8" 1203 | } 1204 | }, 1205 | "node_modules/iconv-lite": { 1206 | "version": "0.6.3", 1207 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 1208 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 1209 | "license": "MIT", 1210 | "dependencies": { 1211 | "safer-buffer": ">= 2.1.2 < 3.0.0" 1212 | }, 1213 | "engines": { 1214 | "node": ">=0.10.0" 1215 | } 1216 | }, 1217 | "node_modules/inflight": { 1218 | "version": "1.0.6", 1219 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1220 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1221 | "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", 1222 | "dev": true, 1223 | "license": "ISC", 1224 | "dependencies": { 1225 | "once": "^1.3.0", 1226 | "wrappy": "1" 1227 | } 1228 | }, 1229 | "node_modules/inherits": { 1230 | "version": "2.0.4", 1231 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1232 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1233 | "license": "ISC" 1234 | }, 1235 | "node_modules/interpret": { 1236 | "version": "1.4.0", 1237 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", 1238 | "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", 1239 | "dev": true, 1240 | "license": "MIT", 1241 | "engines": { 1242 | "node": ">= 0.10" 1243 | } 1244 | }, 1245 | "node_modules/ipaddr.js": { 1246 | "version": "1.9.1", 1247 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1248 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 1249 | "license": "MIT", 1250 | "engines": { 1251 | "node": ">= 0.10" 1252 | } 1253 | }, 1254 | "node_modules/is-core-module": { 1255 | "version": "2.16.1", 1256 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", 1257 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", 1258 | "dev": true, 1259 | "license": "MIT", 1260 | "dependencies": { 1261 | "hasown": "^2.0.2" 1262 | }, 1263 | "engines": { 1264 | "node": ">= 0.4" 1265 | }, 1266 | "funding": { 1267 | "url": "https://github.com/sponsors/ljharb" 1268 | } 1269 | }, 1270 | "node_modules/is-promise": { 1271 | "version": "4.0.0", 1272 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", 1273 | "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", 1274 | "license": "MIT" 1275 | }, 1276 | "node_modules/isexe": { 1277 | "version": "2.0.0", 1278 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1279 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1280 | "license": "ISC" 1281 | }, 1282 | "node_modules/json-schema-traverse": { 1283 | "version": "0.4.1", 1284 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1285 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1286 | "license": "MIT" 1287 | }, 1288 | "node_modules/math-intrinsics": { 1289 | "version": "1.1.0", 1290 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", 1291 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", 1292 | "license": "MIT", 1293 | "engines": { 1294 | "node": ">= 0.4" 1295 | } 1296 | }, 1297 | "node_modules/media-typer": { 1298 | "version": "1.1.0", 1299 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", 1300 | "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", 1301 | "license": "MIT", 1302 | "engines": { 1303 | "node": ">= 0.8" 1304 | } 1305 | }, 1306 | "node_modules/merge-descriptors": { 1307 | "version": "2.0.0", 1308 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", 1309 | "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", 1310 | "license": "MIT", 1311 | "engines": { 1312 | "node": ">=18" 1313 | }, 1314 | "funding": { 1315 | "url": "https://github.com/sponsors/sindresorhus" 1316 | } 1317 | }, 1318 | "node_modules/mime-db": { 1319 | "version": "1.54.0", 1320 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", 1321 | "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", 1322 | "license": "MIT", 1323 | "engines": { 1324 | "node": ">= 0.6" 1325 | } 1326 | }, 1327 | "node_modules/mime-types": { 1328 | "version": "3.0.1", 1329 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", 1330 | "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", 1331 | "license": "MIT", 1332 | "dependencies": { 1333 | "mime-db": "^1.54.0" 1334 | }, 1335 | "engines": { 1336 | "node": ">= 0.6" 1337 | } 1338 | }, 1339 | "node_modules/minimatch": { 1340 | "version": "3.1.2", 1341 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1342 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1343 | "dev": true, 1344 | "license": "ISC", 1345 | "dependencies": { 1346 | "brace-expansion": "^1.1.7" 1347 | }, 1348 | "engines": { 1349 | "node": "*" 1350 | } 1351 | }, 1352 | "node_modules/minimist": { 1353 | "version": "1.2.8", 1354 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 1355 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 1356 | "dev": true, 1357 | "license": "MIT", 1358 | "funding": { 1359 | "url": "https://github.com/sponsors/ljharb" 1360 | } 1361 | }, 1362 | "node_modules/ms": { 1363 | "version": "2.1.3", 1364 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1365 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1366 | "license": "MIT" 1367 | }, 1368 | "node_modules/negotiator": { 1369 | "version": "1.0.0", 1370 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", 1371 | "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", 1372 | "license": "MIT", 1373 | "engines": { 1374 | "node": ">= 0.6" 1375 | } 1376 | }, 1377 | "node_modules/object-assign": { 1378 | "version": "4.1.1", 1379 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1380 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 1381 | "license": "MIT", 1382 | "engines": { 1383 | "node": ">=0.10.0" 1384 | } 1385 | }, 1386 | "node_modules/object-inspect": { 1387 | "version": "1.13.4", 1388 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", 1389 | "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", 1390 | "license": "MIT", 1391 | "engines": { 1392 | "node": ">= 0.4" 1393 | }, 1394 | "funding": { 1395 | "url": "https://github.com/sponsors/ljharb" 1396 | } 1397 | }, 1398 | "node_modules/on-finished": { 1399 | "version": "2.4.1", 1400 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 1401 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 1402 | "license": "MIT", 1403 | "dependencies": { 1404 | "ee-first": "1.1.1" 1405 | }, 1406 | "engines": { 1407 | "node": ">= 0.8" 1408 | } 1409 | }, 1410 | "node_modules/once": { 1411 | "version": "1.4.0", 1412 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1413 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1414 | "license": "ISC", 1415 | "dependencies": { 1416 | "wrappy": "1" 1417 | } 1418 | }, 1419 | "node_modules/parseurl": { 1420 | "version": "1.3.3", 1421 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1422 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 1423 | "license": "MIT", 1424 | "engines": { 1425 | "node": ">= 0.8" 1426 | } 1427 | }, 1428 | "node_modules/path-is-absolute": { 1429 | "version": "1.0.1", 1430 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1431 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1432 | "dev": true, 1433 | "license": "MIT", 1434 | "engines": { 1435 | "node": ">=0.10.0" 1436 | } 1437 | }, 1438 | "node_modules/path-key": { 1439 | "version": "3.1.1", 1440 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1441 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1442 | "license": "MIT", 1443 | "engines": { 1444 | "node": ">=8" 1445 | } 1446 | }, 1447 | "node_modules/path-parse": { 1448 | "version": "1.0.7", 1449 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1450 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1451 | "dev": true, 1452 | "license": "MIT" 1453 | }, 1454 | "node_modules/path-to-regexp": { 1455 | "version": "8.2.0", 1456 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", 1457 | "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", 1458 | "license": "MIT", 1459 | "engines": { 1460 | "node": ">=16" 1461 | } 1462 | }, 1463 | "node_modules/pkce-challenge": { 1464 | "version": "5.0.0", 1465 | "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", 1466 | "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", 1467 | "license": "MIT", 1468 | "engines": { 1469 | "node": ">=16.20.0" 1470 | } 1471 | }, 1472 | "node_modules/proxy-addr": { 1473 | "version": "2.0.7", 1474 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 1475 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 1476 | "license": "MIT", 1477 | "dependencies": { 1478 | "forwarded": "0.2.0", 1479 | "ipaddr.js": "1.9.1" 1480 | }, 1481 | "engines": { 1482 | "node": ">= 0.10" 1483 | } 1484 | }, 1485 | "node_modules/punycode": { 1486 | "version": "2.3.1", 1487 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 1488 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 1489 | "license": "MIT", 1490 | "engines": { 1491 | "node": ">=6" 1492 | } 1493 | }, 1494 | "node_modules/qs": { 1495 | "version": "6.14.0", 1496 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", 1497 | "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", 1498 | "license": "BSD-3-Clause", 1499 | "dependencies": { 1500 | "side-channel": "^1.1.0" 1501 | }, 1502 | "engines": { 1503 | "node": ">=0.6" 1504 | }, 1505 | "funding": { 1506 | "url": "https://github.com/sponsors/ljharb" 1507 | } 1508 | }, 1509 | "node_modules/range-parser": { 1510 | "version": "1.2.1", 1511 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1512 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 1513 | "license": "MIT", 1514 | "engines": { 1515 | "node": ">= 0.6" 1516 | } 1517 | }, 1518 | "node_modules/raw-body": { 1519 | "version": "3.0.0", 1520 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", 1521 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", 1522 | "license": "MIT", 1523 | "dependencies": { 1524 | "bytes": "3.1.2", 1525 | "http-errors": "2.0.0", 1526 | "iconv-lite": "0.6.3", 1527 | "unpipe": "1.0.0" 1528 | }, 1529 | "engines": { 1530 | "node": ">= 0.8" 1531 | } 1532 | }, 1533 | "node_modules/readdirp": { 1534 | "version": "4.1.2", 1535 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", 1536 | "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", 1537 | "license": "MIT", 1538 | "engines": { 1539 | "node": ">= 14.18.0" 1540 | }, 1541 | "funding": { 1542 | "type": "individual", 1543 | "url": "https://paulmillr.com/funding/" 1544 | } 1545 | }, 1546 | "node_modules/rechoir": { 1547 | "version": "0.6.2", 1548 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 1549 | "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", 1550 | "dev": true, 1551 | "dependencies": { 1552 | "resolve": "^1.1.6" 1553 | }, 1554 | "engines": { 1555 | "node": ">= 0.10" 1556 | } 1557 | }, 1558 | "node_modules/resolve": { 1559 | "version": "1.22.10", 1560 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", 1561 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", 1562 | "dev": true, 1563 | "license": "MIT", 1564 | "dependencies": { 1565 | "is-core-module": "^2.16.0", 1566 | "path-parse": "^1.0.7", 1567 | "supports-preserve-symlinks-flag": "^1.0.0" 1568 | }, 1569 | "bin": { 1570 | "resolve": "bin/resolve" 1571 | }, 1572 | "engines": { 1573 | "node": ">= 0.4" 1574 | }, 1575 | "funding": { 1576 | "url": "https://github.com/sponsors/ljharb" 1577 | } 1578 | }, 1579 | "node_modules/resolve-pkg-maps": { 1580 | "version": "1.0.0", 1581 | "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", 1582 | "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", 1583 | "dev": true, 1584 | "license": "MIT", 1585 | "funding": { 1586 | "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 1587 | } 1588 | }, 1589 | "node_modules/router": { 1590 | "version": "2.2.0", 1591 | "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", 1592 | "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", 1593 | "license": "MIT", 1594 | "dependencies": { 1595 | "debug": "^4.4.0", 1596 | "depd": "^2.0.0", 1597 | "is-promise": "^4.0.0", 1598 | "parseurl": "^1.3.3", 1599 | "path-to-regexp": "^8.0.0" 1600 | }, 1601 | "engines": { 1602 | "node": ">= 18" 1603 | } 1604 | }, 1605 | "node_modules/safe-buffer": { 1606 | "version": "5.2.1", 1607 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1608 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1609 | "funding": [ 1610 | { 1611 | "type": "github", 1612 | "url": "https://github.com/sponsors/feross" 1613 | }, 1614 | { 1615 | "type": "patreon", 1616 | "url": "https://www.patreon.com/feross" 1617 | }, 1618 | { 1619 | "type": "consulting", 1620 | "url": "https://feross.org/support" 1621 | } 1622 | ], 1623 | "license": "MIT" 1624 | }, 1625 | "node_modules/safer-buffer": { 1626 | "version": "2.1.2", 1627 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1628 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1629 | "license": "MIT" 1630 | }, 1631 | "node_modules/send": { 1632 | "version": "1.2.0", 1633 | "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", 1634 | "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", 1635 | "license": "MIT", 1636 | "dependencies": { 1637 | "debug": "^4.3.5", 1638 | "encodeurl": "^2.0.0", 1639 | "escape-html": "^1.0.3", 1640 | "etag": "^1.8.1", 1641 | "fresh": "^2.0.0", 1642 | "http-errors": "^2.0.0", 1643 | "mime-types": "^3.0.1", 1644 | "ms": "^2.1.3", 1645 | "on-finished": "^2.4.1", 1646 | "range-parser": "^1.2.1", 1647 | "statuses": "^2.0.1" 1648 | }, 1649 | "engines": { 1650 | "node": ">= 18" 1651 | } 1652 | }, 1653 | "node_modules/serve-static": { 1654 | "version": "2.2.0", 1655 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", 1656 | "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", 1657 | "license": "MIT", 1658 | "dependencies": { 1659 | "encodeurl": "^2.0.0", 1660 | "escape-html": "^1.0.3", 1661 | "parseurl": "^1.3.3", 1662 | "send": "^1.2.0" 1663 | }, 1664 | "engines": { 1665 | "node": ">= 18" 1666 | } 1667 | }, 1668 | "node_modules/setprototypeof": { 1669 | "version": "1.2.0", 1670 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1671 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 1672 | "license": "ISC" 1673 | }, 1674 | "node_modules/shebang-command": { 1675 | "version": "2.0.0", 1676 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1677 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1678 | "license": "MIT", 1679 | "dependencies": { 1680 | "shebang-regex": "^3.0.0" 1681 | }, 1682 | "engines": { 1683 | "node": ">=8" 1684 | } 1685 | }, 1686 | "node_modules/shebang-regex": { 1687 | "version": "3.0.0", 1688 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1689 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1690 | "license": "MIT", 1691 | "engines": { 1692 | "node": ">=8" 1693 | } 1694 | }, 1695 | "node_modules/shelljs": { 1696 | "version": "0.8.5", 1697 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", 1698 | "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", 1699 | "dev": true, 1700 | "license": "BSD-3-Clause", 1701 | "dependencies": { 1702 | "glob": "^7.0.0", 1703 | "interpret": "^1.0.0", 1704 | "rechoir": "^0.6.2" 1705 | }, 1706 | "bin": { 1707 | "shjs": "bin/shjs" 1708 | }, 1709 | "engines": { 1710 | "node": ">=4" 1711 | } 1712 | }, 1713 | "node_modules/shx": { 1714 | "version": "0.3.4", 1715 | "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", 1716 | "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", 1717 | "dev": true, 1718 | "license": "MIT", 1719 | "dependencies": { 1720 | "minimist": "^1.2.3", 1721 | "shelljs": "^0.8.5" 1722 | }, 1723 | "bin": { 1724 | "shx": "lib/cli.js" 1725 | }, 1726 | "engines": { 1727 | "node": ">=6" 1728 | } 1729 | }, 1730 | "node_modules/side-channel": { 1731 | "version": "1.1.0", 1732 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", 1733 | "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", 1734 | "license": "MIT", 1735 | "dependencies": { 1736 | "es-errors": "^1.3.0", 1737 | "object-inspect": "^1.13.3", 1738 | "side-channel-list": "^1.0.0", 1739 | "side-channel-map": "^1.0.1", 1740 | "side-channel-weakmap": "^1.0.2" 1741 | }, 1742 | "engines": { 1743 | "node": ">= 0.4" 1744 | }, 1745 | "funding": { 1746 | "url": "https://github.com/sponsors/ljharb" 1747 | } 1748 | }, 1749 | "node_modules/side-channel-list": { 1750 | "version": "1.0.0", 1751 | "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", 1752 | "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", 1753 | "license": "MIT", 1754 | "dependencies": { 1755 | "es-errors": "^1.3.0", 1756 | "object-inspect": "^1.13.3" 1757 | }, 1758 | "engines": { 1759 | "node": ">= 0.4" 1760 | }, 1761 | "funding": { 1762 | "url": "https://github.com/sponsors/ljharb" 1763 | } 1764 | }, 1765 | "node_modules/side-channel-map": { 1766 | "version": "1.0.1", 1767 | "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", 1768 | "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", 1769 | "license": "MIT", 1770 | "dependencies": { 1771 | "call-bound": "^1.0.2", 1772 | "es-errors": "^1.3.0", 1773 | "get-intrinsic": "^1.2.5", 1774 | "object-inspect": "^1.13.3" 1775 | }, 1776 | "engines": { 1777 | "node": ">= 0.4" 1778 | }, 1779 | "funding": { 1780 | "url": "https://github.com/sponsors/ljharb" 1781 | } 1782 | }, 1783 | "node_modules/side-channel-weakmap": { 1784 | "version": "1.0.2", 1785 | "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", 1786 | "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", 1787 | "license": "MIT", 1788 | "dependencies": { 1789 | "call-bound": "^1.0.2", 1790 | "es-errors": "^1.3.0", 1791 | "get-intrinsic": "^1.2.5", 1792 | "object-inspect": "^1.13.3", 1793 | "side-channel-map": "^1.0.1" 1794 | }, 1795 | "engines": { 1796 | "node": ">= 0.4" 1797 | }, 1798 | "funding": { 1799 | "url": "https://github.com/sponsors/ljharb" 1800 | } 1801 | }, 1802 | "node_modules/statuses": { 1803 | "version": "2.0.1", 1804 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1805 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 1806 | "license": "MIT", 1807 | "engines": { 1808 | "node": ">= 0.8" 1809 | } 1810 | }, 1811 | "node_modules/supports-preserve-symlinks-flag": { 1812 | "version": "1.0.0", 1813 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1814 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1815 | "dev": true, 1816 | "license": "MIT", 1817 | "engines": { 1818 | "node": ">= 0.4" 1819 | }, 1820 | "funding": { 1821 | "url": "https://github.com/sponsors/ljharb" 1822 | } 1823 | }, 1824 | "node_modules/toidentifier": { 1825 | "version": "1.0.1", 1826 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1827 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 1828 | "license": "MIT", 1829 | "engines": { 1830 | "node": ">=0.6" 1831 | } 1832 | }, 1833 | "node_modules/tsx": { 1834 | "version": "4.19.4", 1835 | "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.4.tgz", 1836 | "integrity": "sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==", 1837 | "dev": true, 1838 | "license": "MIT", 1839 | "dependencies": { 1840 | "esbuild": "~0.25.0", 1841 | "get-tsconfig": "^4.7.5" 1842 | }, 1843 | "bin": { 1844 | "tsx": "dist/cli.mjs" 1845 | }, 1846 | "engines": { 1847 | "node": ">=18.0.0" 1848 | }, 1849 | "optionalDependencies": { 1850 | "fsevents": "~2.3.3" 1851 | } 1852 | }, 1853 | "node_modules/type-is": { 1854 | "version": "2.0.1", 1855 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", 1856 | "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", 1857 | "license": "MIT", 1858 | "dependencies": { 1859 | "content-type": "^1.0.5", 1860 | "media-typer": "^1.1.0", 1861 | "mime-types": "^3.0.0" 1862 | }, 1863 | "engines": { 1864 | "node": ">= 0.6" 1865 | } 1866 | }, 1867 | "node_modules/typescript": { 1868 | "version": "5.8.3", 1869 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", 1870 | "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", 1871 | "dev": true, 1872 | "license": "Apache-2.0", 1873 | "bin": { 1874 | "tsc": "bin/tsc", 1875 | "tsserver": "bin/tsserver" 1876 | }, 1877 | "engines": { 1878 | "node": ">=14.17" 1879 | } 1880 | }, 1881 | "node_modules/undici-types": { 1882 | "version": "6.21.0", 1883 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", 1884 | "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", 1885 | "dev": true, 1886 | "license": "MIT" 1887 | }, 1888 | "node_modules/unpipe": { 1889 | "version": "1.0.0", 1890 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1891 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 1892 | "license": "MIT", 1893 | "engines": { 1894 | "node": ">= 0.8" 1895 | } 1896 | }, 1897 | "node_modules/uri-js": { 1898 | "version": "4.4.1", 1899 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1900 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1901 | "license": "BSD-2-Clause", 1902 | "dependencies": { 1903 | "punycode": "^2.1.0" 1904 | } 1905 | }, 1906 | "node_modules/vary": { 1907 | "version": "1.1.2", 1908 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1909 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 1910 | "license": "MIT", 1911 | "engines": { 1912 | "node": ">= 0.8" 1913 | } 1914 | }, 1915 | "node_modules/which": { 1916 | "version": "2.0.2", 1917 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1918 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1919 | "license": "ISC", 1920 | "dependencies": { 1921 | "isexe": "^2.0.0" 1922 | }, 1923 | "bin": { 1924 | "node-which": "bin/node-which" 1925 | }, 1926 | "engines": { 1927 | "node": ">= 8" 1928 | } 1929 | }, 1930 | "node_modules/wrappy": { 1931 | "version": "1.0.2", 1932 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1933 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1934 | "license": "ISC" 1935 | }, 1936 | "node_modules/zod": { 1937 | "version": "3.25.28", 1938 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.28.tgz", 1939 | "integrity": "sha512-/nt/67WYKnr5by3YS7LroZJbtcCBurDKKPBPWWzaxvVCGuG/NOsiKkrjoOhI8mJ+SQUXEbUzeB3S+6XDUEEj7Q==", 1940 | "license": "MIT", 1941 | "funding": { 1942 | "url": "https://github.com/sponsors/colinhacks" 1943 | } 1944 | }, 1945 | "node_modules/zod-to-json-schema": { 1946 | "version": "3.24.5", 1947 | "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", 1948 | "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", 1949 | "license": "ISC", 1950 | "peerDependencies": { 1951 | "zod": "^3.24.1" 1952 | } 1953 | } 1954 | } 1955 | } 1956 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lamemind/mcp-server-multiverse", 3 | "version": "1.1.4", 4 | "homepage": "https://github.com/lamemind/mcp-server-multiverse#readme", 5 | "author": "lamemind", 6 | "type": "module", 7 | "main": "./dist/index.js", 8 | "bin": { 9 | "mcp-server-multiverse": "./dist/index.js" 10 | }, 11 | "files": [ 12 | "dist" 13 | ], 14 | "scripts": { 15 | "build": "tsc && shx chmod +x dist/*.js", 16 | "dev": "tsx watch src/index.ts", 17 | "watch": "tsc --watch", 18 | "start": "node dist/index.js" 19 | }, 20 | "keywords": [ 21 | "mcp", 22 | "model-context-protocol" 23 | ], 24 | "license": "MIT", 25 | "description": "A middleware server that enables multiple isolated instances of the same MCP servers to coexist independently with unique namespaces and configurations.", 26 | "devDependencies": { 27 | "@types/express": "^5.0.0", 28 | "@types/node": "^22.13.5", 29 | "shx": "^0.3.4", 30 | "tsx": "^4.19.3", 31 | "typescript": "^5.7.3" 32 | }, 33 | "dependencies": { 34 | "@modelcontextprotocol/sdk": "^1.12.0", 35 | "chokidar": "^4.0.3", 36 | "commander": "^13.1.0", 37 | "zod-to-json-schema": "^3.24.3" 38 | }, 39 | "repository": { 40 | "type": "git", 41 | "url": "git+https://github.com/lamemind/mcp-server-multiverse.git" 42 | }, 43 | "bugs": { 44 | "url": "https://github.com/lamemind/mcp-server-multiverse/issues" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/inc/json-config.ts: -------------------------------------------------------------------------------- 1 | import {z} from 'zod'; 2 | import * as fs from "node:fs"; 3 | 4 | // Schema per la risoluzione dei path 5 | const PathResolutionSchema = z.object({ 6 | root: z.string().describe("Root path for the resolution"), 7 | applyTo: z.array(z.string()).describe("List of keys to apply the resolution to") 8 | }); 9 | 10 | // Schema per il file watch 11 | const FileWatchSchema = z.object({ 12 | enabled: z.boolean().describe("Whether the file watch is enabled"), 13 | path: z.string().optional().describe("Path to watch for changes") 14 | }); 15 | 16 | // Schema per un singolo server 17 | const ServerSchema = z.object({ 18 | enabled: z.boolean().default(true).describe("Whether this server configuration is enabled"), 19 | command: z.string().describe("Command to run, the same as in 'claude_desktop_config.json'"), 20 | args: z.array(z.string()).describe("Arguments to pass to the command, the same as in 'claude_desktop_config.json'"), 21 | env: z.record(z.string()).optional().describe("Environment variables to set, the same as in 'claude_desktop_config.json'"), 22 | pathResolution: PathResolutionSchema.optional().describe("Relative path resolution configuration"), 23 | fileWatch: FileWatchSchema.optional().describe("File watch configuration"), 24 | hideFunctions: z.array(z.string()).optional().describe("List of function names to hide from this server") 25 | }); 26 | 27 | // Schema principale della configurazione 28 | const ConfigSchema = z.object({ 29 | serverName: z.string().describe("Name of the server to expose to the client"), 30 | functionsPrefix: z.string().describe("Aggregation prefix to use for the functions exposed to the client"), 31 | servers: z.array(ServerSchema).describe("List of MCP servers to wrap") 32 | }); 33 | 34 | // Type inference automatica 35 | type WrapperConfig = z.infer; 36 | type ServerConfig = z.infer; 37 | type PathResolution = z.infer; 38 | 39 | // Funzione di validazione 40 | function validateConfig(config: unknown): WrapperConfig { 41 | console.error(`Validating configuration...`); 42 | return ConfigSchema.parse(config); 43 | } 44 | 45 | function readConfigFile(filePath: string): WrapperConfig { 46 | console.error(`Reading config file from: ${filePath}`); 47 | const jsonContent = fs.readFileSync(filePath, 'utf8'); 48 | const jsonRaw = JSON.parse(jsonContent); 49 | 50 | try { 51 | return validateConfig(jsonRaw); 52 | } catch (error) { 53 | if (error instanceof z.ZodError) { 54 | console.error('Validation errors:', error.errors); 55 | } 56 | throw error; 57 | } 58 | } 59 | 60 | export { WrapperConfig, ServerConfig, PathResolution, readConfigFile }; 61 | -------------------------------------------------------------------------------- /src/inc/main-mcp-server.ts: -------------------------------------------------------------------------------- 1 | import { registerWrappedServer } from "./wrapped-servers.js"; 2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 4 | import { WrapperConfig } from "./json-config.js"; 5 | 6 | async function startMainServer(config: WrapperConfig) { 7 | console.error(`Starting main server with name: ${config.serverName}`); 8 | console.error(`Initializing main MCP server...`); 9 | const mainMcpServer = new McpServer({ 10 | name: config.serverName, 11 | version: "1.0.0" 12 | }, { 13 | capabilities: { 14 | prompts: {}, 15 | resources: {} 16 | } 17 | }); 18 | 19 | mainMcpServer.prompt( 20 | `${config.serverName}_placeholder`, {}, 21 | ({ }) => ({ 22 | messages: [{ 23 | role: "user", 24 | content: { 25 | type: "text", 26 | text: `this is a placeholder prompt to avoid error logs when no prompts are registered` 27 | } 28 | }] 29 | }) 30 | ); 31 | 32 | mainMcpServer.resource( 33 | `${config.serverName}_placeholder`, 34 | `placeholder://${config.serverName}`, 35 | async (uri) => ({ 36 | contents: [{ 37 | uri: uri.href, 38 | text: `This is a placeholder resource to avoid error logs when no resources are registered` 39 | }] 40 | }) 41 | ); 42 | 43 | for (const wrappedConfig of config.servers) { 44 | await registerWrappedServer(mainMcpServer, config, wrappedConfig); 45 | } 46 | 47 | const transport = new StdioServerTransport(); 48 | await mainMcpServer.connect(transport); 49 | 50 | console.error("Server started successfully"); 51 | } 52 | 53 | export { startMainServer }; 54 | -------------------------------------------------------------------------------- /src/inc/server-arguments.ts: -------------------------------------------------------------------------------- 1 | import {program} from "commander"; 2 | 3 | export async function parseCliArguments() { 4 | const cliArgs = { 5 | configFile: '', 6 | }; 7 | 8 | program 9 | .argument('', 'Json config file') 10 | .action((setupFile) => { 11 | cliArgs.configFile = setupFile; 12 | console.error(`Cli Args ${JSON.stringify(cliArgs)}`); 13 | }); 14 | 15 | program.on('error', (err) => { 16 | console.error('Error:', err); 17 | }); 18 | 19 | program.parse(process.argv); 20 | return cliArgs; 21 | } 22 | -------------------------------------------------------------------------------- /src/inc/wrapped-servers.ts: -------------------------------------------------------------------------------- 1 | import {Client} from "@modelcontextprotocol/sdk/client/index.js"; 2 | import {StdioClientTransport} from "@modelcontextprotocol/sdk/client/stdio.js"; 3 | import {ServerConfig, WrapperConfig} from "./json-config.js"; 4 | import {convertJsonSchemaToZodShape} from "./zod-utils.js"; 5 | import {McpServer} from "@modelcontextprotocol/sdk/server/mcp.js"; 6 | import path from "node:path"; 7 | import chokidar from 'chokidar'; 8 | 9 | async function openWrappedServer(serverConfig: ServerConfig) { 10 | console.error(`Opening wrapped server with command: ${serverConfig.command} ${serverConfig.args.join(' ')}`); 11 | const transport = new StdioClientTransport({ 12 | command: serverConfig.command, 13 | args: serverConfig.args, 14 | env: serverConfig.env 15 | }); 16 | 17 | const client = new Client( 18 | { 19 | name: "wrapper-client", 20 | version: "1.0.0" 21 | }, 22 | { 23 | capabilities: { 24 | prompts: {}, 25 | resources: {}, 26 | tools: {} 27 | } 28 | } 29 | ); 30 | 31 | await client.connect(transport); 32 | return client; 33 | } 34 | 35 | /** 36 | * Get the tool name to expose from the main server 37 | * @param config 38 | * @param toolName 39 | */ 40 | function getToolName(config: WrapperConfig, toolName: string) { 41 | return `${config.functionsPrefix}_${toolName}`; 42 | } 43 | 44 | /** 45 | * Apply path resolution to the arguments 46 | * @param args 47 | * @param serverConfig 48 | */ 49 | function applyPathResolution(args: any, serverConfig: ServerConfig) { 50 | serverConfig.pathResolution?.applyTo.forEach((key) => { 51 | if (args[key]) { 52 | const root = (serverConfig.pathResolution as any).root; 53 | const fullPath = path.join(root, args[key]); 54 | console.error(`Rewriting ${key} path ${args[key]} to ${fullPath}`); 55 | args[key] = fullPath; 56 | } 57 | }); 58 | } 59 | 60 | /** 61 | * Register tools from the wrapped server 62 | * @param mainMcpServer 63 | * @param mainConfig 64 | * @param wrappedServer 65 | * @param serverConfig 66 | */ 67 | async function registerTools(mainMcpServer: McpServer, mainConfig: WrapperConfig, 68 | wrappedServer: any, serverConfig: ServerConfig) { 69 | 70 | const {tools} = await wrappedServer.listTools(); 71 | tools.forEach((tool: { inputSchema: any; name: string; description: any; }) => { 72 | // Skip functions that are in the hideFunctions list 73 | if (serverConfig.hideFunctions && serverConfig.hideFunctions.includes(tool.name)) { 74 | console.error(`Skipping hidden function: ${tool.name}`); 75 | return; 76 | } 77 | 78 | const zodShape = convertJsonSchemaToZodShape(tool.inputSchema); 79 | const externalName = getToolName(mainConfig, tool.name); 80 | 81 | const callback = async (args: any) => { 82 | applyPathResolution(args, serverConfig); 83 | 84 | const res = await wrappedServer.callTool({ 85 | name: tool.name, 86 | arguments: args 87 | }); 88 | 89 | return res as { content: { type: "text", text: string }[] }; 90 | }; 91 | 92 | const description = `[Use this tool only in the "${mainConfig.functionsPrefix}" scope] ` + (tool.description || ""); 93 | mainMcpServer.tool(externalName, description, zodShape, callback); 94 | }); 95 | 96 | } 97 | 98 | function instantiateFileWatcher(serverConfig: ServerConfig, fakeServer: any) { 99 | console.error(`Setting up file watcher... 100 | enabled: ${serverConfig.fileWatch?.enabled} 101 | path: ${serverConfig.fileWatch?.path}`); 102 | if (serverConfig.fileWatch?.enabled) { 103 | const filepath = serverConfig.fileWatch.path as string; 104 | 105 | chokidar.watch(filepath).on('change', async (file, stats) => { 106 | console.error(`File watcher triggered for: ${file}`); 107 | fakeServer.instanceRebuild++; 108 | console.error(`File ${file} edited - Rebuild #${fakeServer.instanceRebuild}`); 109 | 110 | fakeServer.wrappedServerInstance.close(); 111 | fakeServer.wrappedServerInstance = await openWrappedServer(serverConfig); 112 | }); 113 | } 114 | } 115 | 116 | async function registerWrappedServer(mainMcpServer: McpServer, mainConfig: WrapperConfig, serverConfig: ServerConfig) { 117 | // Skip registration if the server is disabled 118 | if (serverConfig.enabled === false) { 119 | console.error(`Skipping disabled server: ${serverConfig.command} ${serverConfig.args.join(' ')}`); 120 | return; 121 | } 122 | 123 | console.error(`Registering wrapped server ${serverConfig.command} ${serverConfig.args.join(' ')}`); 124 | 125 | /** 126 | * Fake server is used to allow server instance switch if needed by file watch or auto-restart 127 | */ 128 | const fakeServer = { 129 | instanceRebuild: 0, 130 | wrappedServerInstance: await openWrappedServer(serverConfig), 131 | callTool(args: { name: string, arguments: any }) { 132 | return this.wrappedServerInstance.callTool(args); 133 | }, 134 | listTools() { 135 | return this.wrappedServerInstance.listTools(); 136 | } 137 | } 138 | 139 | await registerTools(mainMcpServer, mainConfig, fakeServer, serverConfig); 140 | 141 | // TODO register resources 142 | // TODO register prompts 143 | 144 | instantiateFileWatcher(serverConfig, fakeServer); 145 | } 146 | 147 | export {registerWrappedServer, getToolName}; 148 | -------------------------------------------------------------------------------- /src/inc/zod-utils.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | function convertPropertyToZod(propSchema: any, isRequired: boolean = true): z.ZodType { 4 | let schema: z.ZodType; 5 | 6 | switch (propSchema.type) { 7 | case 'string': 8 | let stringSchema = z.string(); 9 | if (propSchema.pattern) stringSchema = stringSchema.regex(new RegExp(propSchema.pattern)); 10 | if (propSchema.minLength) stringSchema = stringSchema.min(propSchema.minLength); 11 | if (propSchema.maxLength) stringSchema = stringSchema.max(propSchema.maxLength); 12 | schema = stringSchema; 13 | break; 14 | 15 | case 'number': 16 | case 'integer': 17 | let numberSchema = propSchema.type === 'integer' ? z.number().int() : z.number(); 18 | if (propSchema.minimum !== undefined) numberSchema = numberSchema.min(propSchema.minimum); 19 | if (propSchema.maximum !== undefined) numberSchema = numberSchema.max(propSchema.maximum); 20 | schema = numberSchema; 21 | break; 22 | 23 | case 'boolean': 24 | schema = z.boolean(); 25 | break; 26 | 27 | case 'array': 28 | const itemSchema = propSchema.items ? convertPropertyToZod(propSchema.items) : z.any(); 29 | schema = z.array(itemSchema); 30 | break; 31 | 32 | case 'object': 33 | schema = z.object(jsonPropsToZodShape(propSchema.properties, propSchema.required || [])); 34 | break; 35 | 36 | default: 37 | schema = z.any(); 38 | } 39 | 40 | if (propSchema.description) 41 | schema = schema.describe(propSchema.description); 42 | 43 | return isRequired ? schema : schema.optional(); 44 | } 45 | 46 | function jsonPropsToZodShape(properties: Record, required: string[] = []): z.ZodRawShape { 47 | const shape: z.ZodRawShape = {}; 48 | 49 | if (properties && typeof properties === 'object') 50 | for (const [key, propSchema] of Object.entries(properties)) { 51 | const isRequired = required.includes(key); 52 | shape[key] = convertPropertyToZod(propSchema, isRequired); 53 | } 54 | 55 | return shape; 56 | } 57 | 58 | function convertJsonSchemaToZodShape(schema: any): z.ZodRawShape { 59 | if (schema.type !== 'object' || !schema.properties) { 60 | throw new Error('Schema must be an object type with properties'); 61 | } 62 | 63 | return jsonPropsToZodShape(schema.properties, schema.required || []); 64 | } 65 | 66 | export { convertJsonSchemaToZodShape }; 67 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {parseCliArguments} from "./inc/server-arguments.js"; 4 | import {readConfigFile} from "./inc/json-config.js"; 5 | import {startMainServer} from "./inc/main-mcp-server.js"; 6 | 7 | 8 | (async function () { 9 | console.error(`Starting MCP Server Wrapper...`); 10 | const cliArguments = await parseCliArguments(); 11 | 12 | const wrapperConfig = readConfigFile(cliArguments.configFile); 13 | console.error(wrapperConfig); 14 | 15 | await startMainServer(wrapperConfig); 16 | 17 | })(); 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "outDir": "./dist", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true 12 | } 13 | } 14 | --------------------------------------------------------------------------------