From d1baabae14f9066b29acb39eb95134bd19ac2d7f Mon Sep 17 00:00:00 2001 From: YISH Date: Thu, 8 May 2025 13:27:04 +0800 Subject: [PATCH 1/3] Add support for MCP in export mode --- app/components/mcp-market.tsx | 27 ++++----- app/config/build.ts | 11 ++++ app/mcp/actions.ts | 110 +++++++++++++++++++++++++++++----- app/mcp/client.ts | 50 +++++++++++----- app/mcp/types.ts | 34 ++++++++--- app/store/access.ts | 7 ++- app/typing.ts | 4 ++ next.config.mjs | 6 ++ 8 files changed, 198 insertions(+), 51 deletions(-) diff --git a/app/components/mcp-market.tsx b/app/components/mcp-market.tsx index 235f63b1c..485ffa284 100644 --- a/app/components/mcp-market.tsx +++ b/app/components/mcp-market.tsx @@ -22,11 +22,12 @@ import { resumeMcpServer, } from "../mcp/actions"; import { - ListToolsResponse, + ToolSchema, McpConfigData, PresetServer, ServerConfig, ServerStatusResponse, + isServerStdioConfig, } from "../mcp/types"; import clsx from "clsx"; import PlayIcon from "../icons/play.svg"; @@ -46,7 +47,7 @@ export function McpMarketPage() { const [searchText, setSearchText] = useState(""); const [userConfig, setUserConfig] = useState>({}); const [editingServerId, setEditingServerId] = useState(); - const [tools, setTools] = useState(null); + const [tools, setTools] = useState(null); const [viewingServerId, setViewingServerId] = useState(); const [isLoading, setIsLoading] = useState(false); const [config, setConfig] = useState(); @@ -136,7 +137,7 @@ export function McpMarketPage() { useEffect(() => { if (!editingServerId || !config) return; const currentConfig = config.mcpServers[editingServerId]; - if (currentConfig) { + if (isServerStdioConfig(currentConfig)) { // 从当前配置中提取用户配置 const preset = presetServers.find((s) => s.id === editingServerId); if (preset?.configSchema) { @@ -230,7 +231,7 @@ export function McpMarketPage() { try { const result = await getClientTools(id); if (result) { - setTools(result); + setTools(result?.tools); } else { throw new Error("Failed to load tools"); } @@ -731,17 +732,15 @@ export function McpMarketPage() {
{isLoading ? (
Loading...
- ) : tools?.tools ? ( - tools.tools.map( - (tool: ListToolsResponse["tools"], index: number) => ( -
-
{tool.name}
-
- {tool.description} -
+ ) : tools ? ( + tools.map((tool: ToolSchema, index: number) => ( +
+
{tool.name}
+
+ {tool.description}
- ), - ) +
+ )) ) : (
No tools available
)} diff --git a/app/config/build.ts b/app/config/build.ts index b2b1ad49d..f83bbf37c 100644 --- a/app/config/build.ts +++ b/app/config/build.ts @@ -40,6 +40,17 @@ export const getBuildConfig = () => { buildMode, isApp, template: process.env.DEFAULT_INPUT_TEMPLATE ?? DEFAULT_INPUT_TEMPLATE, + + needCode: !!process.env.CODE, + hideUserApiKey: !!process.env.HIDE_USER_API_KEY, + baseUrl: process.env.BASE_URL, + openaiUrl: process.env.OPENAI_BASE_URL ?? process.env.BASE_URL, + disableGPT4: !!process.env.DISABLE_GPT4, + useCustomConfig: !!process.env.USE_CUSTOM_CONFIG, + hideBalanceQuery: !process.env.ENABLE_BALANCE_QUERY, + disableFastLink: !!process.env.DISABLE_FAST_LINK, + defaultModel: process.env.DEFAULT_MODEL ?? "", + enableMcp: process.env.ENABLE_MCP === "true", }; }; diff --git a/app/mcp/actions.ts b/app/mcp/actions.ts index e8b1ad1d0..e330d2e93 100644 --- a/app/mcp/actions.ts +++ b/app/mcp/actions.ts @@ -1,4 +1,6 @@ -"use server"; +if (!EXPORT_MODE) { + ("use server"); +} import { createClient, executeRequest, @@ -14,14 +16,22 @@ import { ServerConfig, ServerStatusResponse, } from "./types"; -import fs from "fs/promises"; -import path from "path"; -import { getServerSideConfig } from "../config/server"; + +const JSON_INDENT = 2; const logger = new MCPClientLogger("MCP Actions"); -const CONFIG_PATH = path.join(process.cwd(), "app/mcp/mcp_config.json"); + +const getConfigPath = async () => { + if (EXPORT_MODE) { + return "/mcp/config.json"; + } else { + const path = await import("path"); + return path.join(process.cwd(), "app/mcp/mcp_config.json"); + } +}; const clientsMap = new Map(); +const toolToClientMap = new Map(); // 获取客户端状态 export async function getClientsStatus(): Promise< @@ -126,6 +136,13 @@ async function initializeSingleClient( `Supported tools for [${clientId}]: ${JSON.stringify(tools, null, 2)}`, ); clientsMap.set(clientId, { client, tools, errorMsg: null }); + if (tools?.tools) { + for (const tool of tools.tools) { + if (tool.name) { + toolToClientMap.set(tool.name, clientId); + } + } + } logger.success(`Client [${clientId}] initialized successfully`); }) .catch((error) => { @@ -243,6 +260,13 @@ export async function resumeMcpServer(clientId: string): Promise { const client = await createClient(clientId, serverConfig); const tools = await listTools(client); clientsMap.set(clientId, { client, tools, errorMsg: null }); + if (tools?.tools) { + for (const tool of tools.tools) { + if (tool.name) { + toolToClientMap.set(tool.name, clientId); + } + } + } logger.success(`Client [${clientId}] initialized successfully`); // 初始化成功后更新配置 @@ -339,7 +363,19 @@ export async function executeMcpAction( request: McpRequestMessage, ) { try { - const client = clientsMap.get(clientId); + let client = clientsMap.get(clientId); + if ( + !client && + request.params?.name && + typeof request.params.name === "string" + ) { + // Use a tool-to-client mapping that's maintained when tools are initialized + const toolName = request.params.name; + const toolClientId = toolToClientMap.get(toolName); + if (toolClientId) { + client = clientsMap.get(toolClientId); + } + } if (!client?.client) { throw new Error(`Client ${clientId} not found`); } @@ -354,8 +390,30 @@ export async function executeMcpAction( // 获取 MCP 配置文件 export async function getMcpConfigFromFile(): Promise { try { - const configStr = await fs.readFile(CONFIG_PATH, "utf-8"); - return JSON.parse(configStr); + if (EXPORT_MODE) { + const res = await fetch(await getConfigPath()); + const config: McpConfigData = await res.json(); + const storage = localStorage; + const storedConfig_str = storage.getItem("McpConfig"); + if (storedConfig_str) { + const storedConfig: McpConfigData = JSON.parse(storedConfig_str); + // Create a merged configuration that combines both sources + const merged = { ...config.mcpServers }; + if (storedConfig.mcpServers) { + // Ensure we process all servers from stored config + for (const id in storedConfig.mcpServers) { + merged[id] = { ...merged[id], ...storedConfig.mcpServers[id] }; + } + } + + config.mcpServers = merged; + } + return config; + } else { + const fs = await import("fs/promises"); + const configStr = await fs.readFile(await getConfigPath(), "utf-8"); + return JSON.parse(configStr); + } } catch (error) { logger.error(`Failed to load MCP config, using default config: ${error}`); return DEFAULT_MCP_CONFIG; @@ -364,20 +422,42 @@ export async function getMcpConfigFromFile(): Promise { // 更新 MCP 配置文件 async function updateMcpConfig(config: McpConfigData): Promise { - try { + if (EXPORT_MODE) { + try { + const storage = localStorage; + storage.setItem("McpConfig", JSON.stringify(config)); + } catch (storageError) { + logger.warn(`Failed to save MCP config to localStorage: ${storageError}`); + // Continue execution without storage + } + } else { + const fs = await import("fs/promises"); + const path = await import("path"); // 确保目录存在 - await fs.mkdir(path.dirname(CONFIG_PATH), { recursive: true }); - await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2)); - } catch (error) { - throw error; + await fs.mkdir(path.dirname(await getConfigPath()), { recursive: true }); + await fs.writeFile( + await getConfigPath(), + JSON.stringify(config, null, JSON_INDENT), + ); } } // 检查 MCP 是否启用 export async function isMcpEnabled() { try { - const serverConfig = getServerSideConfig(); - return serverConfig.enableMcp; + const config = await getMcpConfigFromFile(); + if (typeof config.enableMcp === "boolean") { + return config.enableMcp; + } + if (EXPORT_MODE) { + const { getClientConfig } = await import("../config/client"); + const clientConfig = getClientConfig(); + return clientConfig?.enableMcp === true; + } else { + const { getServerSideConfig } = await import("../config/server"); + const serverConfig = getServerSideConfig(); + return serverConfig.enableMcp; + } } catch (error) { logger.error(`Failed to check MCP status: ${error}`); return false; diff --git a/app/mcp/client.ts b/app/mcp/client.ts index 5c2f071e3..3154b49f3 100644 --- a/app/mcp/client.ts +++ b/app/mcp/client.ts @@ -1,7 +1,11 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js"; -import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { MCPClientLogger } from "./logger"; -import { ListToolsResponse, McpRequestMessage, ServerConfig } from "./types"; +import { + ListToolsResponse, + McpRequestMessage, + ServerConfig, + isServerSseConfig, +} from "./types"; import { z } from "zod"; const logger = new MCPClientLogger(); @@ -12,18 +16,36 @@ export async function createClient( ): Promise { logger.info(`Creating client for ${id}...`); - const transport = new StdioClientTransport({ - command: config.command, - args: config.args, - env: { - ...Object.fromEntries( - Object.entries(process.env) - .filter(([_, v]) => v !== undefined) - .map(([k, v]) => [k, v as string]), - ), - ...(config.env || {}), - }, - }); + let transport; + + if (isServerSseConfig(config)) { + const { SSEClientTransport } = await import( + "@modelcontextprotocol/sdk/client/sse.js" + ); + transport = new SSEClientTransport(new URL(config.url)); + } else { + if (EXPORT_MODE) { + throw new Error( + "Cannot use stdio transport in export mode. Please use SSE transport configuration instead.", + ); + } else { + const { StdioClientTransport } = await import( + "@modelcontextprotocol/sdk/client/stdio.js" + ); + transport = new StdioClientTransport({ + command: config.command, + args: config.args, + env: { + ...Object.fromEntries( + Object.entries(process.env) + .filter(([_, v]) => v !== undefined) + .map(([k, v]) => [k, v as string]), + ), + ...(config.env || {}), + }, + }); + } + } const client = new Client( { diff --git a/app/mcp/types.ts b/app/mcp/types.ts index 45d1d979a..ea63bb64a 100644 --- a/app/mcp/types.ts +++ b/app/mcp/types.ts @@ -8,6 +8,7 @@ export interface McpRequestMessage { id?: string | number; method: "tools/call" | string; params?: { + name?: string; [key: string]: unknown; }; } @@ -65,12 +66,14 @@ export const McpNotificationsSchema: z.ZodType = z.object({ // Next Chat //////////// export interface ListToolsResponse { - tools: { - name?: string; - description?: string; - inputSchema?: object; - [key: string]: any; - }; + tools: ToolSchema[]; +} + +export interface ToolSchema { + name?: string; + description?: string; + inputSchema?: object; + [key: string]: any; } export type McpClientData = @@ -110,14 +113,31 @@ export interface ServerStatusResponse { } // MCP 服务器配置相关类型 -export interface ServerConfig { + +export const isServerSseConfig = (c?: ServerConfig): c is ServerSseConfig => + c !== null && typeof c === "object" && c.type === "sse"; +export const isServerStdioConfig = (c?: ServerConfig): c is ServerStdioConfig => + c !== null && typeof c === "object" && (!c.type || c.type === "stdio"); + +export type ServerConfig = ServerStdioConfig | ServerSseConfig; + +export interface ServerStdioConfig { + type?: "stdio"; command: string; args: string[]; env?: Record; status?: "active" | "paused" | "error"; } +export interface ServerSseConfig { + type: "sse"; + url: string; + headers?: Record; + status?: "active" | "paused" | "error"; +} + export interface McpConfigData { + enableMcp?: boolean; // MCP Server 的配置 mcpServers: Record; } diff --git a/app/store/access.ts b/app/store/access.ts index 7025a1814..524efb515 100644 --- a/app/store/access.ts +++ b/app/store/access.ts @@ -243,7 +243,12 @@ export const useAccessStore = createPersistStore( ); }, fetch() { - if (fetchState > 0 || getClientConfig()?.buildMode === "export") return; + const clientConfig = getClientConfig(); + if (!(fetchState > 0) && clientConfig?.buildMode === "export") { + set(clientConfig); + fetchState = 2; + } + if (fetchState > 0 || clientConfig?.buildMode === "export") return; fetchState = 1; fetch("/api/config", { method: "post", diff --git a/app/typing.ts b/app/typing.ts index ecb327936..cac15e1b3 100644 --- a/app/typing.ts +++ b/app/typing.ts @@ -1,3 +1,7 @@ +declare global { + const EXPORT_MODE: boolean; +} + export type Updater = (updater: (value: T) => void) => void; export const ROLES = ["system", "user", "assistant"] as const; diff --git a/next.config.mjs b/next.config.mjs index 0e1105d56..afcd1fb75 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -6,9 +6,15 @@ console.log("[Next] build mode", mode); const disableChunk = !!process.env.DISABLE_CHUNK || mode === "export"; console.log("[Next] build with chunk: ", !disableChunk); +const EXPORT_MODE = mode === "export"; + + /** @type {import('next').NextConfig} */ const nextConfig = { webpack(config) { + config.plugins.push(new webpack.DefinePlugin({ + EXPORT_MODE: EXPORT_MODE + })); config.module.rules.push({ test: /\.svg$/, use: ["@svgr/webpack"], From 62d32f317d071efeadf12147570c83c75361e1af Mon Sep 17 00:00:00 2001 From: YISH Date: Thu, 8 May 2025 19:40:04 +0800 Subject: [PATCH 2/3] Split actions.ts into actions.server.ts and actions.client.ts --- app/mcp/actions.base.ts | 491 ++++++++++++++++++++++++++++++++++++ app/mcp/actions.client.ts | 1 + app/mcp/actions.server.ts | 2 + app/mcp/actions.ts | 505 ++++---------------------------------- 4 files changed, 542 insertions(+), 457 deletions(-) create mode 100644 app/mcp/actions.base.ts create mode 100644 app/mcp/actions.client.ts create mode 100644 app/mcp/actions.server.ts diff --git a/app/mcp/actions.base.ts b/app/mcp/actions.base.ts new file mode 100644 index 000000000..ee9776554 --- /dev/null +++ b/app/mcp/actions.base.ts @@ -0,0 +1,491 @@ +import { + createClient, + executeRequest, + listTools, + removeClient, +} from "./client"; +import { MCPClientLogger } from "./logger"; +import { + DEFAULT_MCP_CONFIG, + McpClientData, + McpConfigData, + McpRequestMessage, + ServerConfig, + ServerStatusResponse, +} from "./types"; + +const JSON_INDENT = 2; + +const logger = new MCPClientLogger("MCP Actions"); + +const getConfigPath = async () => { + if (EXPORT_MODE) { + return "/mcp/config.json"; + } else { + const path = await import("path"); + return path.join(process.cwd(), "app/mcp/mcp_config.json"); + } +}; + +class ClientsMap extends Map { + toolToClientMap: Map; + constructor() { + super(); + this.toolToClientMap = new Map(); + } + + set(clientId: string, data: McpClientData): this { + super.set(clientId, data); + + if (data?.tools?.tools) { + for (const tool of data.tools.tools) { + if (tool.name) { + this.toolToClientMap.set(tool.name, clientId); + } + } + } else { + this.purgeToolMappings(clientId); + } + return this; + } + + delete(clientId: string): boolean { + const ret = clientsMap.delete(clientId); + this.purgeToolMappings(clientId); + return ret; + } + + clear(): void { + super.clear(); + this.toolToClientMap.clear(); + } + + getByToolName(toolName: string) { + const toolClientId = clientsMap.toolToClientMap.get(toolName); + if (toolClientId) { + return clientsMap.get(toolClientId); + } + } + + private purgeToolMappings(clientId: string) { + for (const [tool, mappedId] of this.toolToClientMap.entries()) { + if (mappedId === clientId) { + this.toolToClientMap.delete(tool); + } + } + } +} + +const clientsMap = new ClientsMap(); + +// 获取客户端状态 +export async function getClientsStatus(): Promise< + Record +> { + const config = await getMcpConfigFromFile(); + const result: Record = {}; + + for (const clientId of Object.keys(config.mcpServers)) { + const status = clientsMap.get(clientId); + const serverConfig = config.mcpServers[clientId]; + + if (!serverConfig) { + result[clientId] = { status: "undefined", errorMsg: null }; + continue; + } + + if (serverConfig.status === "paused") { + result[clientId] = { status: "paused", errorMsg: null }; + continue; + } + + if (!status) { + result[clientId] = { status: "undefined", errorMsg: null }; + continue; + } + + if ( + status.client === null && + status.tools === null && + status.errorMsg === null + ) { + result[clientId] = { status: "initializing", errorMsg: null }; + continue; + } + + if (status.errorMsg) { + result[clientId] = { status: "error", errorMsg: status.errorMsg }; + continue; + } + + if (status.client) { + result[clientId] = { status: "active", errorMsg: null }; + continue; + } + + result[clientId] = { status: "error", errorMsg: "Client not found" }; + } + + return result; +} + +// 获取客户端工具 +export async function getClientTools(clientId: string) { + return clientsMap.get(clientId)?.tools ?? null; +} + +// 获取可用客户端数量 +export async function getAvailableClientsCount() { + let count = 0; + clientsMap.forEach((map) => !map.errorMsg && count++); + return count; +} + +// 获取所有客户端工具 +export async function getAllTools() { + const result = []; + for (const [clientId, status] of clientsMap.entries()) { + result.push({ + clientId, + tools: status.tools, + }); + } + return result; +} + +// 初始化单个客户端 +async function initializeSingleClient( + clientId: string, + serverConfig: ServerConfig, +) { + // 如果服务器状态是暂停,则不初始化 + if (serverConfig.status === "paused") { + logger.info(`Skipping initialization for paused client [${clientId}]`); + return; + } + + logger.info(`Initializing client [${clientId}]...`); + + // 先设置初始化状态 + clientsMap.set(clientId, { + client: null, + tools: null, + errorMsg: null, // null 表示正在初始化 + }); + + // 异步初始化 + createClient(clientId, serverConfig) + .then(async (client) => { + const tools = await listTools(client); + logger.info( + `Supported tools for [${clientId}]: ${JSON.stringify(tools, null, 2)}`, + ); + clientsMap.set(clientId, { client, tools, errorMsg: null }); + logger.success(`Client [${clientId}] initialized successfully`); + }) + .catch((error) => { + clientsMap.set(clientId, { + client: null, + tools: null, + errorMsg: error instanceof Error ? error.message : String(error), + }); + logger.error(`Failed to initialize client [${clientId}]: ${error}`); + }); +} + +// 初始化系统 +export async function initializeMcpSystem() { + logger.info("MCP Actions starting..."); + try { + // 检查是否已有活跃的客户端 + if (clientsMap.size > 0) { + logger.info("MCP system already initialized, skipping..."); + return; + } + + const config = await getMcpConfigFromFile(); + // 初始化所有客户端 + for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { + await initializeSingleClient(clientId, serverConfig); + } + return config; + } catch (error) { + logger.error(`Failed to initialize MCP system: ${error}`); + throw error; + } +} + +// 添加服务器 +export async function addMcpServer(clientId: string, config: ServerConfig) { + try { + const currentConfig = await getMcpConfigFromFile(); + const isNewServer = !(clientId in currentConfig.mcpServers); + + // 如果是新服务器,设置默认状态为 active + if (isNewServer && !config.status) { + config.status = "active"; + } + + const newConfig = { + ...currentConfig, + mcpServers: { + ...currentConfig.mcpServers, + [clientId]: config, + }, + }; + await updateMcpConfig(newConfig); + + // 只有新服务器或状态为 active 的服务器才初始化 + if (isNewServer || config.status === "active") { + await initializeSingleClient(clientId, config); + } + + return newConfig; + } catch (error) { + logger.error(`Failed to add server [${clientId}]: ${error}`); + throw error; + } +} + +// 暂停服务器 +export async function pauseMcpServer(clientId: string) { + try { + const currentConfig = await getMcpConfigFromFile(); + const serverConfig = currentConfig.mcpServers[clientId]; + if (!serverConfig) { + throw new Error(`Server ${clientId} not found`); + } + + // 先更新配置 + const newConfig: McpConfigData = { + ...currentConfig, + mcpServers: { + ...currentConfig.mcpServers, + [clientId]: { + ...serverConfig, + status: "paused", + }, + }, + }; + await updateMcpConfig(newConfig); + + // 然后关闭客户端 + const client = clientsMap.get(clientId); + if (client?.client) { + await removeClient(client.client); + } + clientsMap.delete(clientId); + + return newConfig; + } catch (error) { + logger.error(`Failed to pause server [${clientId}]: ${error}`); + throw error; + } +} + +// 恢复服务器 +export async function resumeMcpServer(clientId: string): Promise { + try { + const currentConfig = await getMcpConfigFromFile(); + const serverConfig = currentConfig.mcpServers[clientId]; + if (!serverConfig) { + throw new Error(`Server ${clientId} not found`); + } + + // 先尝试初始化客户端 + logger.info(`Trying to initialize client [${clientId}]...`); + try { + const client = await createClient(clientId, serverConfig); + const tools = await listTools(client); + clientsMap.set(clientId, { client, tools, errorMsg: null }); + logger.success(`Client [${clientId}] initialized successfully`); + + // 初始化成功后更新配置 + const newConfig: McpConfigData = { + ...currentConfig, + mcpServers: { + ...currentConfig.mcpServers, + [clientId]: { + ...serverConfig, + status: "active" as const, + }, + }, + }; + await updateMcpConfig(newConfig); + } catch (error) { + const currentConfig = await getMcpConfigFromFile(); + const serverConfig = currentConfig.mcpServers[clientId]; + + // 如果配置中存在该服务器,则更新其状态为 error + if (serverConfig) { + serverConfig.status = "error"; + await updateMcpConfig(currentConfig); + } + + // 初始化失败 + clientsMap.set(clientId, { + client: null, + tools: null, + errorMsg: error instanceof Error ? error.message : String(error), + }); + logger.error(`Failed to initialize client [${clientId}]: ${error}`); + throw error; + } + } catch (error) { + logger.error(`Failed to resume server [${clientId}]: ${error}`); + throw error; + } +} + +// 移除服务器 +export async function removeMcpServer(clientId: string) { + try { + const currentConfig = await getMcpConfigFromFile(); + const { [clientId]: _, ...rest } = currentConfig.mcpServers; + const newConfig = { + ...currentConfig, + mcpServers: rest, + }; + await updateMcpConfig(newConfig); + + // 关闭并移除客户端 + const client = clientsMap.get(clientId); + if (client?.client) { + await removeClient(client.client); + } + clientsMap.delete(clientId); + + return newConfig; + } catch (error) { + logger.error(`Failed to remove server [${clientId}]: ${error}`); + throw error; + } +} + +// 重启所有客户端 +export async function restartAllClients() { + logger.info("Restarting all clients..."); + try { + // 关闭所有客户端 + for (const client of clientsMap.values()) { + if (client.client) { + await removeClient(client.client); + } + } + + // 清空状态 + clientsMap.clear(); + + // 重新初始化 + const config = await getMcpConfigFromFile(); + for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { + await initializeSingleClient(clientId, serverConfig); + } + return config; + } catch (error) { + logger.error(`Failed to restart clients: ${error}`); + throw error; + } +} + +// 执行 MCP 请求 +export async function executeMcpAction( + clientId: string, + request: McpRequestMessage, +) { + try { + let client = clientsMap.get(clientId); + if ( + !client && + request.params?.name && + typeof request.params.name === "string" + ) { + client = clientsMap.getByToolName(request.params.name); + } + if (!client?.client) { + throw new Error(`Client ${clientId} not found`); + } + logger.info(`Executing request for [${clientId}]`); + return await executeRequest(client.client, request); + } catch (error) { + logger.error(`Failed to execute request for [${clientId}]: ${error}`); + throw error; + } +} + +// 获取 MCP 配置文件 +export async function getMcpConfigFromFile(): Promise { + try { + if (EXPORT_MODE) { + const res = await fetch(await getConfigPath()); + const config: McpConfigData = await res.json(); + const storage = localStorage; + const storedConfig_str = storage.getItem("McpConfig"); + if (storedConfig_str) { + const storedConfig: McpConfigData = JSON.parse(storedConfig_str); + // Create a merged configuration that combines both sources + const merged = { ...config.mcpServers }; + if (storedConfig.mcpServers) { + // Ensure we process all servers from stored config + for (const id in storedConfig.mcpServers) { + merged[id] = { ...merged[id], ...storedConfig.mcpServers[id] }; + } + } + + config.mcpServers = merged; + } + return config; + } else { + const fs = await import("fs/promises"); + const configStr = await fs.readFile(await getConfigPath(), "utf-8"); + return JSON.parse(configStr); + } + } catch (error) { + logger.error(`Failed to load MCP config, using default config: ${error}`); + return DEFAULT_MCP_CONFIG; + } +} + +// 更新 MCP 配置文件 +async function updateMcpConfig(config: McpConfigData): Promise { + if (EXPORT_MODE) { + try { + const storage = localStorage; + storage.setItem("McpConfig", JSON.stringify(config)); + } catch (storageError) { + logger.warn(`Failed to save MCP config to localStorage: ${storageError}`); + // Continue execution without storage + } + } else { + const fs = await import("fs/promises"); + const path = await import("path"); + // 确保目录存在 + await fs.mkdir(path.dirname(await getConfigPath()), { recursive: true }); + await fs.writeFile( + await getConfigPath(), + JSON.stringify(config, null, JSON_INDENT), + ); + } +} + +// 检查 MCP 是否启用 +export async function isMcpEnabled() { + try { + const config = await getMcpConfigFromFile(); + if (typeof config.enableMcp === "boolean") { + return config.enableMcp; + } + if (EXPORT_MODE) { + const { getClientConfig } = await import("../config/client"); + const clientConfig = getClientConfig(); + return clientConfig?.enableMcp === true; + } else { + const { getServerSideConfig } = await import("../config/server"); + const serverConfig = getServerSideConfig(); + return serverConfig.enableMcp; + } + } catch (error) { + logger.error(`Failed to check MCP status: ${error}`); + return false; + } +} diff --git a/app/mcp/actions.client.ts b/app/mcp/actions.client.ts new file mode 100644 index 000000000..e42cff35d --- /dev/null +++ b/app/mcp/actions.client.ts @@ -0,0 +1 @@ +export * from "./actions.base"; diff --git a/app/mcp/actions.server.ts b/app/mcp/actions.server.ts new file mode 100644 index 000000000..bc4b4dc4f --- /dev/null +++ b/app/mcp/actions.server.ts @@ -0,0 +1,2 @@ +"use server"; +export * from "./actions.base"; diff --git a/app/mcp/actions.ts b/app/mcp/actions.ts index e330d2e93..1c603b104 100644 --- a/app/mcp/actions.ts +++ b/app/mcp/actions.ts @@ -1,465 +1,56 @@ -if (!EXPORT_MODE) { - ("use server"); -} -import { - createClient, - executeRequest, - listTools, - removeClient, -} from "./client"; -import { MCPClientLogger } from "./logger"; -import { - DEFAULT_MCP_CONFIG, - McpClientData, - McpConfigData, - McpRequestMessage, - ServerConfig, - ServerStatusResponse, -} from "./types"; +import { McpRequestMessage, ServerConfig } from "./types"; -const JSON_INDENT = 2; +let actionsHost: typeof import("./actions.base") | undefined; -const logger = new MCPClientLogger("MCP Actions"); - -const getConfigPath = async () => { - if (EXPORT_MODE) { - return "/mcp/config.json"; - } else { - const path = await import("path"); - return path.join(process.cwd(), "app/mcp/mcp_config.json"); +const actions = async () => { + if (!actionsHost) { + if (EXPORT_MODE) { + actionsHost = await import("./actions.client"); + } else { + actionsHost = await import("./actions.server"); + } } + + return actionsHost; }; -const clientsMap = new Map(); -const toolToClientMap = new Map(); +export const getAvailableClientsCount = async () => { + return (await actions()).getAvailableClientsCount(); +}; +export const isMcpEnabled = async () => { + return (await actions()).isMcpEnabled(); +}; +export const initializeMcpSystem = async () => { + return (await actions()).initializeMcpSystem(); +}; +export const addMcpServer = async (clientId: string, config: ServerConfig) => { + return (await actions()).addMcpServer(clientId, config); +}; -// 获取客户端状态 -export async function getClientsStatus(): Promise< - Record -> { - const config = await getMcpConfigFromFile(); - const result: Record = {}; - - for (const clientId of Object.keys(config.mcpServers)) { - const status = clientsMap.get(clientId); - const serverConfig = config.mcpServers[clientId]; - - if (!serverConfig) { - result[clientId] = { status: "undefined", errorMsg: null }; - continue; - } - - if (serverConfig.status === "paused") { - result[clientId] = { status: "paused", errorMsg: null }; - continue; - } - - if (!status) { - result[clientId] = { status: "undefined", errorMsg: null }; - continue; - } - - if ( - status.client === null && - status.tools === null && - status.errorMsg === null - ) { - result[clientId] = { status: "initializing", errorMsg: null }; - continue; - } - - if (status.errorMsg) { - result[clientId] = { status: "error", errorMsg: status.errorMsg }; - continue; - } - - if (status.client) { - result[clientId] = { status: "active", errorMsg: null }; - continue; - } - - result[clientId] = { status: "error", errorMsg: "Client not found" }; - } - - return result; -} - -// 获取客户端工具 -export async function getClientTools(clientId: string) { - return clientsMap.get(clientId)?.tools ?? null; -} - -// 获取可用客户端数量 -export async function getAvailableClientsCount() { - let count = 0; - clientsMap.forEach((map) => !map.errorMsg && count++); - return count; -} - -// 获取所有客户端工具 -export async function getAllTools() { - const result = []; - for (const [clientId, status] of clientsMap.entries()) { - result.push({ - clientId, - tools: status.tools, - }); - } - return result; -} - -// 初始化单个客户端 -async function initializeSingleClient( - clientId: string, - serverConfig: ServerConfig, -) { - // 如果服务器状态是暂停,则不初始化 - if (serverConfig.status === "paused") { - logger.info(`Skipping initialization for paused client [${clientId}]`); - return; - } - - logger.info(`Initializing client [${clientId}]...`); - - // 先设置初始化状态 - clientsMap.set(clientId, { - client: null, - tools: null, - errorMsg: null, // null 表示正在初始化 - }); - - // 异步初始化 - createClient(clientId, serverConfig) - .then(async (client) => { - const tools = await listTools(client); - logger.info( - `Supported tools for [${clientId}]: ${JSON.stringify(tools, null, 2)}`, - ); - clientsMap.set(clientId, { client, tools, errorMsg: null }); - if (tools?.tools) { - for (const tool of tools.tools) { - if (tool.name) { - toolToClientMap.set(tool.name, clientId); - } - } - } - logger.success(`Client [${clientId}] initialized successfully`); - }) - .catch((error) => { - clientsMap.set(clientId, { - client: null, - tools: null, - errorMsg: error instanceof Error ? error.message : String(error), - }); - logger.error(`Failed to initialize client [${clientId}]: ${error}`); - }); -} - -// 初始化系统 -export async function initializeMcpSystem() { - logger.info("MCP Actions starting..."); - try { - // 检查是否已有活跃的客户端 - if (clientsMap.size > 0) { - logger.info("MCP system already initialized, skipping..."); - return; - } - - const config = await getMcpConfigFromFile(); - // 初始化所有客户端 - for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { - await initializeSingleClient(clientId, serverConfig); - } - return config; - } catch (error) { - logger.error(`Failed to initialize MCP system: ${error}`); - throw error; - } -} - -// 添加服务器 -export async function addMcpServer(clientId: string, config: ServerConfig) { - try { - const currentConfig = await getMcpConfigFromFile(); - const isNewServer = !(clientId in currentConfig.mcpServers); - - // 如果是新服务器,设置默认状态为 active - if (isNewServer && !config.status) { - config.status = "active"; - } - - const newConfig = { - ...currentConfig, - mcpServers: { - ...currentConfig.mcpServers, - [clientId]: config, - }, - }; - await updateMcpConfig(newConfig); - - // 只有新服务器或状态为 active 的服务器才初始化 - if (isNewServer || config.status === "active") { - await initializeSingleClient(clientId, config); - } - - return newConfig; - } catch (error) { - logger.error(`Failed to add server [${clientId}]: ${error}`); - throw error; - } -} - -// 暂停服务器 -export async function pauseMcpServer(clientId: string) { - try { - const currentConfig = await getMcpConfigFromFile(); - const serverConfig = currentConfig.mcpServers[clientId]; - if (!serverConfig) { - throw new Error(`Server ${clientId} not found`); - } - - // 先更新配置 - const newConfig: McpConfigData = { - ...currentConfig, - mcpServers: { - ...currentConfig.mcpServers, - [clientId]: { - ...serverConfig, - status: "paused", - }, - }, - }; - await updateMcpConfig(newConfig); - - // 然后关闭客户端 - const client = clientsMap.get(clientId); - if (client?.client) { - await removeClient(client.client); - } - clientsMap.delete(clientId); - - return newConfig; - } catch (error) { - logger.error(`Failed to pause server [${clientId}]: ${error}`); - throw error; - } -} - -// 恢复服务器 -export async function resumeMcpServer(clientId: string): Promise { - try { - const currentConfig = await getMcpConfigFromFile(); - const serverConfig = currentConfig.mcpServers[clientId]; - if (!serverConfig) { - throw new Error(`Server ${clientId} not found`); - } - - // 先尝试初始化客户端 - logger.info(`Trying to initialize client [${clientId}]...`); - try { - const client = await createClient(clientId, serverConfig); - const tools = await listTools(client); - clientsMap.set(clientId, { client, tools, errorMsg: null }); - if (tools?.tools) { - for (const tool of tools.tools) { - if (tool.name) { - toolToClientMap.set(tool.name, clientId); - } - } - } - logger.success(`Client [${clientId}] initialized successfully`); - - // 初始化成功后更新配置 - const newConfig: McpConfigData = { - ...currentConfig, - mcpServers: { - ...currentConfig.mcpServers, - [clientId]: { - ...serverConfig, - status: "active" as const, - }, - }, - }; - await updateMcpConfig(newConfig); - } catch (error) { - const currentConfig = await getMcpConfigFromFile(); - const serverConfig = currentConfig.mcpServers[clientId]; - - // 如果配置中存在该服务器,则更新其状态为 error - if (serverConfig) { - serverConfig.status = "error"; - await updateMcpConfig(currentConfig); - } - - // 初始化失败 - clientsMap.set(clientId, { - client: null, - tools: null, - errorMsg: error instanceof Error ? error.message : String(error), - }); - logger.error(`Failed to initialize client [${clientId}]: ${error}`); - throw error; - } - } catch (error) { - logger.error(`Failed to resume server [${clientId}]: ${error}`); - throw error; - } -} - -// 移除服务器 -export async function removeMcpServer(clientId: string) { - try { - const currentConfig = await getMcpConfigFromFile(); - const { [clientId]: _, ...rest } = currentConfig.mcpServers; - const newConfig = { - ...currentConfig, - mcpServers: rest, - }; - await updateMcpConfig(newConfig); - - // 关闭并移除客户端 - const client = clientsMap.get(clientId); - if (client?.client) { - await removeClient(client.client); - } - clientsMap.delete(clientId); - - return newConfig; - } catch (error) { - logger.error(`Failed to remove server [${clientId}]: ${error}`); - throw error; - } -} - -// 重启所有客户端 -export async function restartAllClients() { - logger.info("Restarting all clients..."); - try { - // 关闭所有客户端 - for (const client of clientsMap.values()) { - if (client.client) { - await removeClient(client.client); - } - } - - // 清空状态 - clientsMap.clear(); - - // 重新初始化 - const config = await getMcpConfigFromFile(); - for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { - await initializeSingleClient(clientId, serverConfig); - } - return config; - } catch (error) { - logger.error(`Failed to restart clients: ${error}`); - throw error; - } -} - -// 执行 MCP 请求 -export async function executeMcpAction( +export const getClientsStatus = async () => { + return (await actions()).getClientsStatus(); +}; +export const getClientTools = async (clientId: string) => { + return (await actions()).getClientTools(clientId); +}; +export const getMcpConfigFromFile = async () => { + return (await actions()).getMcpConfigFromFile(); +}; +export const pauseMcpServer = async (clientId: string) => { + return (await actions()).pauseMcpServer(clientId); +}; +export const restartAllClients = async () => { + return (await actions()).restartAllClients(); +}; +export const resumeMcpServer = async (clientId: string) => { + return (await actions()).resumeMcpServer(clientId); +}; +export const executeMcpAction = async ( clientId: string, request: McpRequestMessage, -) { - try { - let client = clientsMap.get(clientId); - if ( - !client && - request.params?.name && - typeof request.params.name === "string" - ) { - // Use a tool-to-client mapping that's maintained when tools are initialized - const toolName = request.params.name; - const toolClientId = toolToClientMap.get(toolName); - if (toolClientId) { - client = clientsMap.get(toolClientId); - } - } - if (!client?.client) { - throw new Error(`Client ${clientId} not found`); - } - logger.info(`Executing request for [${clientId}]`); - return await executeRequest(client.client, request); - } catch (error) { - logger.error(`Failed to execute request for [${clientId}]: ${error}`); - throw error; - } -} - -// 获取 MCP 配置文件 -export async function getMcpConfigFromFile(): Promise { - try { - if (EXPORT_MODE) { - const res = await fetch(await getConfigPath()); - const config: McpConfigData = await res.json(); - const storage = localStorage; - const storedConfig_str = storage.getItem("McpConfig"); - if (storedConfig_str) { - const storedConfig: McpConfigData = JSON.parse(storedConfig_str); - // Create a merged configuration that combines both sources - const merged = { ...config.mcpServers }; - if (storedConfig.mcpServers) { - // Ensure we process all servers from stored config - for (const id in storedConfig.mcpServers) { - merged[id] = { ...merged[id], ...storedConfig.mcpServers[id] }; - } - } - - config.mcpServers = merged; - } - return config; - } else { - const fs = await import("fs/promises"); - const configStr = await fs.readFile(await getConfigPath(), "utf-8"); - return JSON.parse(configStr); - } - } catch (error) { - logger.error(`Failed to load MCP config, using default config: ${error}`); - return DEFAULT_MCP_CONFIG; - } -} - -// 更新 MCP 配置文件 -async function updateMcpConfig(config: McpConfigData): Promise { - if (EXPORT_MODE) { - try { - const storage = localStorage; - storage.setItem("McpConfig", JSON.stringify(config)); - } catch (storageError) { - logger.warn(`Failed to save MCP config to localStorage: ${storageError}`); - // Continue execution without storage - } - } else { - const fs = await import("fs/promises"); - const path = await import("path"); - // 确保目录存在 - await fs.mkdir(path.dirname(await getConfigPath()), { recursive: true }); - await fs.writeFile( - await getConfigPath(), - JSON.stringify(config, null, JSON_INDENT), - ); - } -} - -// 检查 MCP 是否启用 -export async function isMcpEnabled() { - try { - const config = await getMcpConfigFromFile(); - if (typeof config.enableMcp === "boolean") { - return config.enableMcp; - } - if (EXPORT_MODE) { - const { getClientConfig } = await import("../config/client"); - const clientConfig = getClientConfig(); - return clientConfig?.enableMcp === true; - } else { - const { getServerSideConfig } = await import("../config/server"); - const serverConfig = getServerSideConfig(); - return serverConfig.enableMcp; - } - } catch (error) { - logger.error(`Failed to check MCP status: ${error}`); - return false; - } -} +) => { + return (await actions()).executeMcpAction(clientId, request); +}; +export const getAllTools = async () => { + return (await actions()).getAllTools(); +}; From 2f20905544d62224a0edd3cc85a446da4f6eda5c Mon Sep 17 00:00:00 2001 From: YISH Date: Tue, 20 May 2025 00:02:30 +0800 Subject: [PATCH 3/3] Add StreamableHttp support --- app/mcp/client.ts | 14 +- app/mcp/types.ts | 14 +- package.json | 2 +- yarn.lock | 477 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 485 insertions(+), 22 deletions(-) diff --git a/app/mcp/client.ts b/app/mcp/client.ts index 3154b49f3..20561d8cb 100644 --- a/app/mcp/client.ts +++ b/app/mcp/client.ts @@ -1,11 +1,6 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { MCPClientLogger } from "./logger"; -import { - ListToolsResponse, - McpRequestMessage, - ServerConfig, - isServerSseConfig, -} from "./types"; +import { ListToolsResponse, McpRequestMessage, ServerConfig } from "./types"; import { z } from "zod"; const logger = new MCPClientLogger(); @@ -18,11 +13,16 @@ export async function createClient( let transport; - if (isServerSseConfig(config)) { + if (config.type === "sse") { const { SSEClientTransport } = await import( "@modelcontextprotocol/sdk/client/sse.js" ); transport = new SSEClientTransport(new URL(config.url)); + } else if (config.type === "streamable") { + const { StreamableHTTPClientTransport } = await import( + "@modelcontextprotocol/sdk/client/streamableHttp.js" + ); + transport = new StreamableHTTPClientTransport(new URL(config.url)); } else { if (EXPORT_MODE) { throw new Error( diff --git a/app/mcp/types.ts b/app/mcp/types.ts index ea63bb64a..7f35c4589 100644 --- a/app/mcp/types.ts +++ b/app/mcp/types.ts @@ -116,10 +116,15 @@ export interface ServerStatusResponse { export const isServerSseConfig = (c?: ServerConfig): c is ServerSseConfig => c !== null && typeof c === "object" && c.type === "sse"; +export const isStreamableSseConfig = (c?: ServerConfig): c is ServerSseConfig => + c !== null && typeof c === "object" && c.type === "streamable"; export const isServerStdioConfig = (c?: ServerConfig): c is ServerStdioConfig => c !== null && typeof c === "object" && (!c.type || c.type === "stdio"); -export type ServerConfig = ServerStdioConfig | ServerSseConfig; +export type ServerConfig = + | ServerStdioConfig + | ServerSseConfig + | ServerSteamableConfig; export interface ServerStdioConfig { type?: "stdio"; @@ -136,6 +141,13 @@ export interface ServerSseConfig { status?: "active" | "paused" | "error"; } +export interface ServerSteamableConfig { + type: "streamable"; + url: string; + headers?: Record; + status?: "active" | "paused" | "error"; +} + export interface McpConfigData { enableMcp?: boolean; // MCP Server 的配置 diff --git a/package.json b/package.json index ceb92d7fc..eb669c8ff 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dependencies": { "@fortaine/fetch-event-source": "^3.0.6", "@hello-pangea/dnd": "^16.5.0", - "@modelcontextprotocol/sdk": "^1.0.4", + "@modelcontextprotocol/sdk": "^1.11.4", "@next/third-parties": "^14.1.0", "@svgr/webpack": "^6.5.1", "@vercel/analytics": "^0.1.11", diff --git a/yarn.lock b/yarn.lock index a99ff0804..ee8ee9b4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1797,14 +1797,22 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@modelcontextprotocol/sdk@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.0.4.tgz#34ad1edd3db7dd7154e782312dfb29d2d0c11d21" - integrity sha512-C+jw1lF6HSGzs7EZpzHbXfzz9rj9him4BaoumlTciW/IDDgIpweF/qiCWKlP02QKg5PPcgY6xY2WCt5y2tpYow== +"@modelcontextprotocol/sdk@^1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.11.4.tgz#2021c76e208874e1b8551ee24609d921c3372bde" + integrity sha512-OTbhe5slIjiOtLxXhKalkKGhIQrwvhgCDs/C2r8kcBTy5HR/g43aDQU0l7r8O0VGbJPTNJvDc7ZdQMdQDJXmbw== dependencies: + ajv "^8.17.1" content-type "^1.0.5" + cors "^2.8.5" + cross-spawn "^7.0.5" + eventsource "^3.0.2" + express "^5.0.1" + express-rate-limit "^7.5.0" + pkce-challenge "^5.0.0" raw-body "^3.0.0" zod "^3.23.8" + zod-to-json-schema "^3.24.1" "@next/env@14.1.1": version "14.1.1" @@ -2636,6 +2644,14 @@ abab@^2.0.6: resolved "https://registry.npmmirror.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== +accepts@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" + integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng== + dependencies: + mime-types "^3.0.0" + negotiator "^1.0.0" + acorn-globals@^7.0.0: version "7.0.1" resolved "https://registry.npmmirror.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" @@ -2706,6 +2722,16 @@ ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -2979,6 +3005,21 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +body-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa" + integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg== + dependencies: + bytes "^3.1.2" + content-type "^1.0.5" + debug "^4.4.0" + http-errors "^2.0.0" + iconv-lite "^0.6.3" + on-finished "^2.4.1" + qs "^6.14.0" + raw-body "^3.0.0" + type-is "^2.0.0" + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -3048,11 +3089,19 @@ busboy@1.6.0: dependencies: streamsearch "^1.1.0" -bytes@3.1.2: +bytes@3.1.2, bytes@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -3061,6 +3110,14 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -3294,6 +3351,13 @@ concurrently@^8.2.2: tree-kill "^1.2.2" yargs "^17.7.2" +content-disposition@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2" + integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg== + dependencies: + safe-buffer "5.2.1" + content-type@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" @@ -3309,6 +3373,16 @@ convert-source-map@^2.0.0: resolved "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookie-signature@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" + integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== + +cookie@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + core-js-compat@^3.25.1: version "3.29.1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.29.1.tgz#15c0fb812ea27c973c18d425099afa50b934b41b" @@ -3316,6 +3390,14 @@ core-js-compat@^3.25.1: dependencies: browserslist "^4.21.5" +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + cose-base@^1.0.0: version "1.0.3" resolved "https://registry.npmmirror.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a" @@ -3375,6 +3457,15 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + css-box-model@^1.2.1: version "1.2.1" resolved "https://registry.npmmirror.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" @@ -3793,6 +3884,13 @@ debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: dependencies: ms "2.1.2" +debug@^4.3.5, debug@^4.4.0: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + decimal.js@^10.4.2: version "10.4.3" resolved "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" @@ -3863,7 +3961,7 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -depd@2.0.0: +depd@2.0.0, depd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -3971,11 +4069,25 @@ domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + electron-to-chromium@^1.4.284: version "1.4.345" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.345.tgz#c90b7183b39245cddf0e990337469063bfced6f0" @@ -4018,6 +4130,11 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +encodeurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + enhanced-resolve@^5.12.0: version "5.12.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" @@ -4091,6 +4208,16 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: unbox-primitive "^1.0.2" which-typed-array "^1.1.9" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + es-get-iterator@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" @@ -4111,6 +4238,13 @@ es-module-lexer@^1.2.1: resolved "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -4175,6 +4309,11 @@ escalade@^3.1.2: resolved "https://registry.npmmirror.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -4451,11 +4590,28 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +etag@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + events@^3.2.0: version "3.3.0" resolved "https://registry.npmmirror.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +eventsource-parser@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.2.tgz#0fea1abd26eca8201099ff5212f6c4e7ca2fd5d3" + integrity sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA== + +eventsource@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-3.0.7.tgz#1157622e2f5377bb6aef2114372728ba0c156989" + integrity sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA== + dependencies: + eventsource-parser "^3.0.1" + exec-sh@^0.2.0: version "0.2.2" resolved "https://registry.npmmirror.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" @@ -4509,6 +4665,44 @@ expect@^29.0.0, expect@^29.7.0: jest-message-util "^29.7.0" jest-util "^29.7.0" +express-rate-limit@^7.5.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.0.tgz#6a67990a724b4fbbc69119419feef50c51e8b28f" + integrity sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg== + +express@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9" + integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA== + dependencies: + accepts "^2.0.0" + body-parser "^2.2.0" + content-disposition "^1.0.0" + content-type "^1.0.5" + cookie "^0.7.1" + cookie-signature "^1.2.1" + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + finalhandler "^2.1.0" + fresh "^2.0.0" + http-errors "^2.0.0" + merge-descriptors "^2.0.0" + mime-types "^3.0.0" + on-finished "^2.4.1" + once "^1.4.0" + parseurl "^1.3.3" + proxy-addr "^2.0.7" + qs "^6.14.0" + range-parser "^1.2.1" + router "^2.2.0" + send "^1.1.0" + serve-static "^2.2.0" + statuses "^2.0.1" + type-is "^2.0.1" + vary "^1.1.2" + extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -4545,6 +4739,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + fastq@^1.6.0: version "1.15.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" @@ -4588,6 +4787,18 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +finalhandler@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f" + integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q== + dependencies: + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + on-finished "^2.4.1" + parseurl "^1.3.3" + statuses "^2.0.1" + find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -4655,6 +4866,16 @@ formdata-polyfill@^4.0.10: dependencies: fetch-blob "^3.1.2" +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" + integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -4719,11 +4940,35 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.npmmirror.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -4841,6 +5086,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -4883,6 +5133,11 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" @@ -5026,7 +5281,7 @@ html-to-image@^1.11.11: resolved "https://registry.npmmirror.com/html-to-image/-/html-to-image-1.11.11.tgz#c0f8a34dc9e4b97b93ff7ea286eb8562642ebbea" integrity sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA== -http-errors@2.0.0: +http-errors@2.0.0, http-errors@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== @@ -5069,7 +5324,7 @@ husky@^8.0.0: resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== -iconv-lite@0.6, iconv-lite@0.6.3: +iconv-lite@0.6, iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -5154,6 +5409,11 @@ internmap@^1.0.0: resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -5293,6 +5553,11 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.npmmirror.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== +is-promise@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" + integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -5884,6 +6149,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -6153,6 +6423,11 @@ marked@^4.0.14: resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + mdast-util-definitions@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" @@ -6305,11 +6580,21 @@ mdn-data@2.0.14: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== +media-typer@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" + integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== + memoize-one@^6.0.0: version "6.0.0" resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== +merge-descriptors@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808" + integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -6652,6 +6937,11 @@ mime-db@1.52.0: resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +mime-db@^1.54.0: + version "1.54.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + mime-types@^2.1.12, mime-types@^2.1.27: version "2.1.35" resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" @@ -6659,6 +6949,13 @@ mime-types@^2.1.12, mime-types@^2.1.27: dependencies: mime-db "1.52.0" +mime-types@^3.0.0, mime-types@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce" + integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA== + dependencies: + mime-db "^1.54.0" + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -6696,7 +6993,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -6716,6 +7013,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +negotiator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" + integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== + neo-async@^2.6.2: version "2.6.2" resolved "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -6814,7 +7116,7 @@ nwsapi@^2.2.2: resolved "https://registry.npmmirror.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== -object-assign@^4.1.1: +object-assign@^4, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -6824,6 +7126,11 @@ object-inspect@^1.12.3, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + object-is@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" @@ -6882,7 +7189,14 @@ object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" -once@^1.3.0: +on-finished@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -6993,6 +7307,11 @@ parse5@^7.0.0, parse5@^7.1.1: dependencies: entities "^4.4.0" +parseurl@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -7018,6 +7337,11 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4" + integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -7048,6 +7372,11 @@ pirates@^4.0.4: resolved "https://registry.npmmirror.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== +pkce-challenge@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.0.tgz#c3a405cb49e272094a38e890a2b51da0228c4d97" + integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ== + pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.npmmirror.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -7121,6 +7450,14 @@ property-information@^6.0.0: resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.2.0.tgz#b74f522c31c097b5149e3c3cb8d7f3defd986a1d" integrity sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg== +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -7146,6 +7483,13 @@ pure-rand@^6.0.0: resolved "https://registry.npmmirror.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== +qs@^6.14.0: + version "6.14.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + querystringify@^2.1.1: version "2.2.0" resolved "https://registry.npmmirror.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -7168,6 +7512,11 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + raw-body@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f" @@ -7406,6 +7755,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -7495,6 +7849,17 @@ robust-predicates@^3.0.0: resolved "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a" integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g== +router@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" + integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ== + dependencies: + debug "^4.4.0" + depd "^2.0.0" + is-promise "^4.0.0" + parseurl "^1.3.3" + path-to-regexp "^8.0.0" + "rt-client@https://github.com/Azure-Samples/aoai-realtime-audio-sdk/releases/download/js/v0.5.0/rt-client-0.5.0.tgz": version "0.5.0" resolved "https://github.com/Azure-Samples/aoai-realtime-audio-sdk/releases/download/js/v0.5.0/rt-client-0.5.0.tgz#abf2e9a850201e3571b8d36830f77bc52af3de9b" @@ -7534,7 +7899,7 @@ sade@^1.7.3: dependencies: mri "^1.1.0" -safe-buffer@^5.1.0: +safe-buffer@5.2.1, safe-buffer@^5.1.0: version "5.2.1" resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -7602,6 +7967,23 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" +send@^1.1.0, send@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212" + integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw== + dependencies: + debug "^4.3.5" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + fresh "^2.0.0" + http-errors "^2.0.0" + mime-types "^3.0.1" + ms "^2.1.3" + on-finished "^2.4.1" + range-parser "^1.2.1" + statuses "^2.0.1" + serialize-javascript@^6.0.1: version "6.0.1" resolved "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" @@ -7609,6 +7991,16 @@ serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" +serve-static@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9" + integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ== + dependencies: + encodeurl "^2.0.0" + escape-html "^1.0.3" + parseurl "^1.3.3" + send "^1.2.0" + setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" @@ -7631,6 +8023,35 @@ shell-quote@^1.8.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -7640,6 +8061,17 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -7744,7 +8176,7 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -statuses@2.0.1: +statuses@2.0.1, statuses@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== @@ -8145,6 +8577,15 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +type-is@^2.0.0, type-is@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" + integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== + dependencies: + content-type "^1.0.5" + media-typer "^1.1.0" + mime-types "^3.0.0" + typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -8362,6 +8803,11 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.0.0" +vary@^1, vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + vfile-location@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-4.1.0.tgz#69df82fb9ef0a38d0d02b90dd84620e120050dd0" @@ -8632,6 +9078,11 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +zod-to-json-schema@^3.24.1: + version "3.24.5" + resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3" + integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g== + zod@^3.23.8, zod@^3.24.1: version "3.24.1" resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.1.tgz#27445c912738c8ad1e9de1bea0359fa44d9d35ee"