diff --git a/.eslintignore b/.eslintignore index 197d4f77..8fc1b9be 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,7 @@ **/node_modules/* **/out/* **/.next/* +**/dist/* coverage/* diff --git a/.gitignore b/.gitignore index fa70ebdb..c362f8cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # dependencies /node_modules +genkit/node_modules + +# ai session data +genkit/data # next.js /.next/ @@ -15,6 +19,7 @@ npm-debug.log* /.env*.local /.env.development /.env.production +genkit/.env # typescript *.tsbuildinfo @@ -31,6 +36,7 @@ npm-debug.log* # Build Dir /out +genkit/dist # python venv diff --git a/.prettierignore b/.prettierignore index 96fc277a..a660d379 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,10 +5,14 @@ package.json package-lock.json node_modules +genkit/package.json +genkit/package-lock.json +genkit/node_modules # build out coverage +genkit/dist # python venv diff --git a/README.md b/README.md index b0615514..32ac3b71 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,23 @@ Using Node.js version `20.10.0`, run `npm install` in the root directory of the ## Using the development server +### Running the web app only + The app can be run for development using `npm run dev`, and accessed at `http://localhost:3000`. +### Running the Genkit server only + +The Genkit server can be run for development using `npm run genkit:dev`, and accessed at `http://localhost:3100`. + +### Running both services together + +To run both the web app and Genkit server together, use `npm run dev:all`. This will start: + +- The web app at `http://localhost:3000` +- The Genkit server at `http://localhost:3100` + +This is the recommended approach for development, especially when working with features that require both services, such as the chat component. + ## Building the app locally Run `npm run build:local` to build. The built app can be run using `npm start`, and accessed at `http://localhost:3000`. diff --git a/app/components/Chat/components/Chat.tsx b/app/components/Chat/components/Chat.tsx new file mode 100644 index 00000000..43f97d87 --- /dev/null +++ b/app/components/Chat/components/Chat.tsx @@ -0,0 +1,271 @@ +import React, { useState, useEffect, useRef } from "react"; +import { + Box, + TextField, + Button, + Typography, + Paper, + CircularProgress, +} from "@mui/material"; +import SendIcon from "@mui/icons-material/Send"; +import ReactMarkdown from "react-markdown"; +import { styled } from "@mui/material/styles"; + +// Define message interface +interface ChatMessage { + content: string; + role: "user" | "assistant"; +} + +interface ChatProps { + sessionId?: string | null; +} + +// Styled components +const ChatContainer = styled(Box)(() => ({ + display: "flex", + flexDirection: "column", + height: "100%", + overflow: "hidden", + width: "100%", +})); + +const ChatMessages = styled(Box)(({ theme }) => ({ + backgroundColor: theme.palette.background.default, + display: "flex", + flex: 1, + flexDirection: "column", + gap: theme.spacing(2), + overflowY: "auto", + padding: theme.spacing(2), + paddingTop: theme.spacing(3), +})); + +const MessageBubble = styled(Paper, { + shouldForwardProp: (prop) => prop !== "isUser", +})<{ isUser: boolean }>(({ isUser, theme }) => ({ + "& p": { + margin: 0, + }, + alignSelf: isUser ? "flex-end" : "flex-start", + animation: "fadeIn 0.3s ease", + backgroundColor: isUser + ? theme.palette.primary.main + : theme.palette.background.paper, + borderBottomLeftRadius: isUser ? theme.spacing(2) : theme.spacing(0.5), + borderBottomRightRadius: isUser ? theme.spacing(0.5) : theme.spacing(2), + borderRadius: theme.spacing(2), + color: isUser + ? theme.palette.primary.contrastText + : theme.palette.text.primary, + maxWidth: "90%", + overflowWrap: "break-word", + padding: theme.spacing(1.5, 2), + width: "auto", + wordBreak: "break-word", +})); + +const ErrorMessage = styled(Typography)(({ theme }) => ({ + backgroundColor: theme.palette.error.light, + borderRadius: theme.shape.borderRadius, + color: theme.palette.error.main, + fontSize: "0.875rem", + margin: theme.spacing(1, 0), + padding: theme.spacing(1), +})); + +// API endpoint +const API_URL = "http://localhost:3100/api/chat"; + +export const Chat: React.FC = ({ + sessionId: initialSessionId = null, +}) => { + // Chat state + const [messages, setMessages] = useState([]); + const [userInput, setUserInput] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [sessionId, setSessionId] = useState(initialSessionId); + const messagesEndRef = useRef(null); + + // Load session data + const loadSession = async (): Promise => { + try { + setIsLoading(true); + setError(null); + + // In a real implementation, you would fetch the session data from the server + // For now, we'll just set a welcome message + setMessages([ + { + content: + "Hi! I'm BioBuddy. I can help you with information about organisms, assemblies, workflows, and more. How can I assist you today?", + role: "assistant", + }, + ]); + } catch (err) { + const errorMessage = err instanceof Error ? err.message : String(err); + setError(`Failed to load session: ${errorMessage}`); + console.error("Error loading session:", err); + } finally { + setIsLoading(false); + } + }; + + // Scroll to bottom of messages + const scrollToBottom = (): void => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + + useEffect(() => { + scrollToBottom(); + }, [messages]); + + useEffect(() => { + if (sessionId) { + // TODO: Load session data from server + loadSession(); + } else { + setMessages([ + { + content: + "Hi! I'm BioBuddy. I can help you with information about organisms, assemblies, workflows, and more. How can I assist you today?", + role: "assistant", + }, + ]); + } + }, [sessionId]); + + useEffect(() => { + if (sessionId !== initialSessionId && initialSessionId !== null) { + // TODO: Load session data from server + loadSession(); + setSessionId(initialSessionId); + } + }, [initialSessionId, sessionId]); + + // Send message to the backend + const sendMessage = async (): Promise => { + if (!userInput.trim()) return; + + const userMessage = userInput.trim(); + setUserInput(""); + + // Add user message to chat + setMessages((prev) => [...prev, { content: userMessage, role: "user" }]); + + try { + setIsLoading(true); + setError(null); + + const response = await fetch(API_URL, { + body: JSON.stringify({ + message: userMessage, + ...(sessionId ? { session_id: sessionId } : {}), + }), + headers: { + "Content-Type": "application/json", + }, + method: "POST", + }); + + if (!response.ok) { + throw new Error(`Error: ${response.status}`); + } + + const data = await response.json(); + + // Store the session ID for future requests + if (data.sessionId) { + setSessionId(data.sessionId); + console.log(`Using session ID: ${data.sessionId}`); + } + + // Add assistant response to chat + setMessages((prev) => [ + ...prev, + { content: data.response, role: "assistant" }, + ]); + } catch (err) { + const errorMessage = err instanceof Error ? err.message : String(err); + setError(`Failed to send message: ${errorMessage}`); + console.error("Error sending message:", err); + } finally { + setIsLoading(false); + } + }; + + // Handle form submission + const handleSubmit = (e: React.FormEvent): void => { + e.preventDefault(); + sendMessage(); + }; + + // Handle Enter key press + const handleKeyDown = (e: React.KeyboardEvent): void => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + sendMessage(); + } + }; + + return ( + + + {messages.map((message, index) => ( + + {message.content} + + ))} + + {isLoading && ( + + + + )} + + {error && {error}} + +
+ + + theme.palette.background.paper, + borderTop: (theme) => `1px solid ${theme.palette.divider}`, + display: "flex", + gap: (theme) => theme.spacing(1), + padding: (theme) => theme.spacing(2), + }} + > + setUserInput(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Type your message here..." + multiline + rows={3} + fullWidth + disabled={isLoading} + variant="outlined" + size="small" + /> + + + + + ); +}; + +export default Chat; diff --git a/app/components/Chat/components/MinimizableChat.tsx b/app/components/Chat/components/MinimizableChat.tsx new file mode 100644 index 00000000..f627d6c0 --- /dev/null +++ b/app/components/Chat/components/MinimizableChat.tsx @@ -0,0 +1,131 @@ +import React, { useState } from "react"; +import { Box, Fab, Typography } from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { Chat } from "./Chat"; +import Image from "next/image"; + +interface MinimizableChatProps { + initiallyMinimized?: boolean; + sessionId?: string | null; +} + +export const MinimizableChat: React.FC = ({ + initiallyMinimized = true, + sessionId = null, +}) => { + const [isMinimized, setIsMinimized] = useState(initiallyMinimized); + + const toggleChat = (): void => { + setIsMinimized(!isMinimized); + }; + + return ( + + {isMinimized ? ( + + + BioBuddy + + + ) : ( + + + + + BioBuddy + + + BioBuddy Assistant + + + + + + + + + + + )} + + ); +}; + +export default MinimizableChat; diff --git a/app/components/Chat/index.ts b/app/components/Chat/index.ts new file mode 100644 index 00000000..2e6e807d --- /dev/null +++ b/app/components/Chat/index.ts @@ -0,0 +1 @@ +export { Chat } from "./components/Chat"; diff --git a/app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/LaunchStep/launchStep.tsx b/app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/LaunchStep/launchStep.tsx deleted file mode 100644 index b728bd51..00000000 --- a/app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/LaunchStep/launchStep.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Step } from "@databiosphere/findable-ui/lib/components/Stepper/components/Step/step"; -import { StepContent } from "@databiosphere/findable-ui/lib/components/Stepper/components/Step/components/StepContent/stepContent"; -import { StepLabel } from "@databiosphere/findable-ui/lib/components/Stepper/components/Step/components/StepLabel/stepLabel"; -import { StepProps } from "../types"; -import { Button } from "@mui/material"; -import { BUTTON_PROPS } from "@databiosphere/findable-ui/lib/components/common/Button/constants"; -import { StepWarning } from "../components/StepWarning/stepWarning"; -import { getStepActiveState, getButtonDisabledState } from "../utils/stepUtils"; - -export const LaunchStep = ({ - active, - completed, - entryLabel, - index, - onContinue, - onLaunchGalaxy, - status, -}: StepProps): JSX.Element => { - // This step doesn't auto-skip on error - user should see the warning - - return ( - - {entryLabel} - - - - - - ); -}; diff --git a/app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/LaunchStep/step.ts b/app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/LaunchStep/step.ts deleted file mode 100644 index 0feb0dcd..00000000 --- a/app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/LaunchStep/step.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { StepConfig } from "../types"; -import { LaunchStep } from "./launchStep"; - -export const STEP = { - Step: LaunchStep, - key: "referenceAssembly", // Reuse an existing key but won't actually configure anything - label: "Launch Workflow", - renderValue(): string | undefined { - return undefined; - }, -} satisfies StepConfig; diff --git a/genkit/.env.example b/genkit/.env.example new file mode 100644 index 00000000..33ea68cf --- /dev/null +++ b/genkit/.env.example @@ -0,0 +1,24 @@ +# GenKit Configuration +MODEL_PROVIDER=google +MODEL_NAME=gemini-2.5-flash +MODEL_TEMPERATURE=0.3 + +# API Keys (uncomment and add your keys as needed) +# GOOGLE_API_KEY=your_google_api_key +# OPENAI_API_KEY=your_openai_api_key +# ANTHROPIC_API_KEY=your_anthropic_api_key + +# Server Configuration +PORT=3100 +HOST=localhost + +# Paths to catalog output files +CATALOG_OUTPUT_PATH=../catalog/output + +# Galaxy MCP Configuration +GALAXY_MCP_PATH=/home/dcallan-adm/Documents/brc-analytics/galaxy-mcp +GALAXY_URL=https://usegalaxy.org +# GALAXY_API_KEY=your_galaxy_api_key + +# NCBI Datasets API Configuration +# NCBI_API_KEY=your_ncbi_api_key diff --git a/genkit/README.md b/genkit/README.md new file mode 100644 index 00000000..2fdfdb68 --- /dev/null +++ b/genkit/README.md @@ -0,0 +1,146 @@ +# BRC Analytics GenKit Backend + +This directory contains a GenKit backend for the BRC Analytics web application. The backend provides a chat interface and tools to access data from the BRC Analytics catalog. + +## Features + +- Chat interface for interacting with BRC Analytics data +- Tools for accessing organisms, assemblies, workflows, and outbreaks data +- Galaxy MCP integration for interacting with Galaxy bioinformatics platform +- RESTful API for integration with the React frontend + +## Setup + +1. Install dependencies: + +```bash +cd genkit +npm install +``` + +2. Configure environment variables: + +Copy the example environment file and modify as needed: + +```bash +cp .env.example .env +``` + +Edit the `.env` file to configure: + +- Model provider (Google AI, OpenAI, Anthropic, Ollama) +- API keys +- Server port and host +- Path to catalog output files +- Galaxy MCP configuration (path and credentials) + +## Development + +Start the development server: + +```bash +npm run dev +``` + +This will start the GenKit server at http://localhost:3100 (or the port specified in your .env file). + +## API Endpoints + +- `GET /health` - Health check endpoint +- `POST /api/chat` - Chat endpoint + - Request body: `{ "message": "your message", "session_id": "optional_session_id" }` + - Response: `{ "response": "assistant response" }` + +## Available Tools + +The GenKit backend provides the following tools for accessing BRC Analytics data: + +### BRC Analytics Catalog Tools + +- `get_organisms` - Get a list of all organisms +- `get_organism_details` - Get detailed information about a specific organism +- `get_assemblies` - Get a list of all assemblies +- `get_assembly_details` - Get detailed information about a specific assembly +- `get_workflows` - Get a list of all workflows +- `get_workflow_details` - Get detailed information about a specific workflow +- `get_outbreaks` - Get a list of all outbreaks +- `get_outbreak_details` - Get detailed information about a specific outbreak + +### Galaxy MCP Integration Tools + +- `getGalaxyServerInfo` - Get information about the connected Galaxy server +- `getIwcWorkflows` - Get a list of workflows from the Interoperable Workflow Catalog (IWC) +- `searchIwcWorkflows` - Search for workflows in the IWC by query string +- `importWorkflowFromIwc` - Import a workflow from IWC into Galaxy +- `getGalaxyHistories` - Get a list of histories from the Galaxy server +- `getHistoryDetails` - Get detailed information about a specific Galaxy history, including datasets +- `searchGalaxyTools` - Search for tools in the Galaxy server by name +- `createGalaxyHistory` - Create a new history in the Galaxy server + +### NCBI Datasets API Tools + +#### Genome Tools + +- `getGenomeAnnotationReport` - Get genome annotation report for a specific genome assembly accession +- `getGenomeDatasetReport` - Get genome dataset report for specific genome assembly accessions +- `getGenomeSequenceReports` - Get genome sequence reports for a specific genome assembly accession +- `getGenomeByAssemblyNameDatasetReport` - Get genome dataset report for specific assembly names +- `getGenomeByBioprojectDatasetReport` - Get genome dataset report for specific BioProject IDs +- `getGenomeByBiosampleDatasetReport` - Get genome dataset report for specific BioSample IDs +- `getGenomeByTaxonDatasetReport` - Get genome dataset report for specific taxonomy IDs + +#### Gene Tools + +- `getGeneByAccession` - Get gene data for specific gene accessions +- `getGeneOrthologs` - Get gene orthologs for a specific gene ID +- `getGeneById` - Get gene data for specific gene IDs +- `getGeneLinks` - Get gene links for specific gene IDs +- `getGeneByTaxon` - Get gene data for a specific taxonomy ID +- `getGeneChromosomeSummary` - Get gene chromosome summary for a specific taxonomy ID and annotation name + +#### Taxonomy Tools + +- `getTaxonomyDatasetReport` - Get taxonomy dataset report for specific taxonomy IDs +- `getTaxonomyNameReport` - Get taxonomy name report for specific taxonomy IDs + +#### Other Tools + +- `getBiosampleReport` - Get BioSample report for specific BioSample accessions +- `getOrganelleDatasetReport` - Get organelle dataset report for specific organelle accessions + +## Building for Production + +Build the TypeScript code: + +```bash +npm run build +``` + +Start the production server: + +```bash +npm start +``` + +## Integration with React Frontend + +The GenKit backend can be integrated with the React frontend by making API calls to the chat endpoint. Example: + +```javascript +// Example React code +async function sendChatMessage(message, sessionId) { + const response = await fetch("http://localhost:3100/api/chat", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + message, + session_id: sessionId, + }), + }); + + const data = await response.json(); + return data.response; +} +``` diff --git a/genkit/package-lock.json b/genkit/package-lock.json new file mode 100644 index 00000000..c97c3095 --- /dev/null +++ b/genkit/package-lock.json @@ -0,0 +1,4329 @@ +{ + "name": "brc-analytics-genkit", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "brc-analytics-genkit", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@genkit-ai/compat-oai": "^1.15.5", + "@genkit-ai/googleai": "^1.15.5", + "@types/multer": "^2.0.0", + "axios": "^1.11.0", + "dotenv": "^17.2.1", + "express": "^5.1.0", + "genkit": "^1.16.0", + "genkitx-anthropic": "^0.23.1", + "genkitx-mcp": "^1.14.1", + "genkitx-ollama": "^1.15.5", + "multer": "^2.0.2" + }, + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/dotenv": "^6.1.1", + "@types/express": "^5.0.3", + "@types/node": "^20.11.0", + "concurrently": "^9.2.0", + "cors": "^2.8.5", + "ts-node": "^10.9.2", + "ts-node-dev": "^2.0.0", + "typescript": "^5.3.3" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.39.0.tgz", + "integrity": "sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg==", + "license": "MIT", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { + "version": "18.19.122", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.122.tgz", + "integrity": "sha512-yzegtT82dwTNEe/9y+CM8cgb42WrUfMMCg2QqSddzO1J6uPmBD7qKCZ7dOHZP2Yrpm/kb0eqdNMn2MUyEiqBmA==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@genkit-ai/ai": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@genkit-ai/ai/-/ai-1.16.0.tgz", + "integrity": "sha512-Up1xdX1Ha4zE27E4ql6hEiLLlaZQXFCmynkqAko5P8SOxF/s39Oyj95cX/0wULxRsh6XJqv+Pqi/tMDdQuq+bw==", + "license": "Apache-2.0", + "dependencies": { + "@genkit-ai/core": "1.16.0", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.11.19", + "colorette": "^2.0.20", + "dotprompt": "^1.1.1", + "json5": "^2.2.3", + "node-fetch": "^3.3.2", + "partial-json": "^0.1.7", + "uri-templates": "^0.2.0", + "uuid": "^10.0.0" + } + }, + "node_modules/@genkit-ai/compat-oai": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@genkit-ai/compat-oai/-/compat-oai-1.16.0.tgz", + "integrity": "sha512-GKmc1Y/2V9FSFufOONjFx1ZYRuywSLgI2c5gwJBDA0qGzmEzukoUHFwEqrY3Z0kVgcOLVZlvL3NnsaBlXZRQ0A==", + "license": "Apache-2.0", + "dependencies": { + "openai": "^4.95.0" + }, + "peerDependencies": { + "genkit": "^1.16.0" + } + }, + "node_modules/@genkit-ai/core": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@genkit-ai/core/-/core-1.16.0.tgz", + "integrity": "sha512-Avfb0Dh/Zuflcst5HShBHfEcEQFv3NZ6PsSFvLXDAMeocj3Gfn6Rec2K2qAoSbLTtYvFXeXzjMi8eFnMS3QrOg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "~1.25.0", + "@opentelemetry/core": "~1.25.0", + "@opentelemetry/sdk-metrics": "~1.25.0", + "@opentelemetry/sdk-node": "^0.52.0", + "@opentelemetry/sdk-trace-base": "~1.25.0", + "@types/json-schema": "^7.0.15", + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "async-mutex": "^0.5.0", + "body-parser": "^1.20.3", + "cors": "^2.8.5", + "dotprompt": "^1.1.1", + "express": "^4.21.0", + "get-port": "^5.1.0", + "json-schema": "^0.4.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.22.4" + } + }, + "node_modules/@genkit-ai/core/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@genkit-ai/core/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/@genkit-ai/core/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@genkit-ai/core/node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@genkit-ai/core/node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@genkit-ai/core/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@genkit-ai/core/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@genkit-ai/core/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/@genkit-ai/core/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/core/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/@genkit-ai/core/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@genkit-ai/core/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@genkit-ai/core/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@genkit-ai/core/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@genkit-ai/core/node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@genkit-ai/core/node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@genkit-ai/core/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@genkit-ai/core/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@genkit-ai/googleai": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@genkit-ai/googleai/-/googleai-1.16.0.tgz", + "integrity": "sha512-0GTR+d9HIvaMXSpA4SfhkZkkRQrMC+LGfgJPqbJ+iDequlqu8szd4LKQyvNsIb1eFA8bXP6w0T4+AILtDRmYyw==", + "license": "Apache-2.0", + "dependencies": { + "@google/generative-ai": "^0.24.0", + "google-auth-library": "^9.6.3", + "node-fetch": "^3.3.2" + }, + "peerDependencies": { + "genkit": "^1.16.0" + } + }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.4.tgz", + "integrity": "sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.2.tgz", + "integrity": "sha512-EFLRNXR/ixpXQWu6/3Cu30ndDFIFNaqUXcTqsGebujeMan9FzhAaFFswLRiFj61rgygDRr8WO1N+UijjgRxX9g==", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "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" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.52.1.tgz", + "integrity": "sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.25.1.tgz", + "integrity": "sha512-UW/ge9zjvAEmRWVapOP0qyCvPulWU6cQxGxDbWEFfGOj1VBBZAuOqTo3X6yWmDTD3Xe15ysCZChHncr2xFMIfQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz", + "integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.52.1.tgz", + "integrity": "sha512-pVkSH20crBwMTqB3nIN4jpQKUEoB0Z94drIHpYyEqs7UBr+I0cpYyOR3bqjA/UasQUMROb3GX8ZX4/9cVRqGBQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.25.1", + "@opentelemetry/otlp-grpc-exporter-base": "0.52.1", + "@opentelemetry/otlp-transformer": "0.52.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.52.1.tgz", + "integrity": "sha512-05HcNizx0BxcFKKnS5rwOV+2GevLTVIRA0tRgWYyw4yCgR53Ic/xk83toYKts7kbzcI+dswInUg/4s8oyA+tqg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1", + "@opentelemetry/otlp-exporter-base": "0.52.1", + "@opentelemetry/otlp-transformer": "0.52.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.52.1.tgz", + "integrity": "sha512-pt6uX0noTQReHXNeEslQv7x311/F1gJzMnp1HD2qgypLRPbXDeMzzeTngRTUaUbP6hqWNtPxuLr4DEoZG+TcEQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1", + "@opentelemetry/otlp-exporter-base": "0.52.1", + "@opentelemetry/otlp-transformer": "0.52.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.25.1.tgz", + "integrity": "sha512-RmOwSvkimg7ETwJbUOPTMhJm9A9bG1U8s7Zo3ajDh4zM7eYcycQ0dM7FbLD6NXWbI2yj7UY4q8BKinKYBQksyw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1", + "@opentelemetry/semantic-conventions": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.52.1.tgz", + "integrity": "sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.52.1", + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.52.1.tgz", + "integrity": "sha512-z175NXOtX5ihdlshtYBe5RpGeBoTXVCKPPLiQlD6FHvpM4Ch+p2B0yWKYSrBfLH24H9zjJiBdTrtD+hLlfnXEQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1", + "@opentelemetry/otlp-transformer": "0.52.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.52.1.tgz", + "integrity": "sha512-zo/YrSDmKMjG+vPeA9aBBrsQM9Q/f2zo6N04WMB3yNldJRsgpRBeLLwvAt/Ba7dpehDLOEFBd1i2JCoaFtpCoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.25.1", + "@opentelemetry/otlp-exporter-base": "0.52.1", + "@opentelemetry/otlp-transformer": "0.52.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.52.1.tgz", + "integrity": "sha512-I88uCZSZZtVa0XniRqQWKbjAUm73I8tpEy/uJYPPYw5d7BRdVk0RfTBQw8kSUl01oVWEuqxLDa802222MYyWHg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.52.1", + "@opentelemetry/core": "1.25.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/sdk-logs": "0.52.1", + "@opentelemetry/sdk-metrics": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.25.1.tgz", + "integrity": "sha512-p6HFscpjrv7//kE+7L+3Vn00VEDUJB0n6ZrjkTYHrJ58QZ8B3ajSJhRbCcY6guQ3PDjTbxWklyvIN2ojVbIb1A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.25.1.tgz", + "integrity": "sha512-nBprRf0+jlgxks78G/xq72PipVK+4or9Ypntw0gVZYNTCSK8rg5SeaGV19tV920CMqBD/9UIOiFr23Li/Q8tiA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.25.1.tgz", + "integrity": "sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1", + "@opentelemetry/semantic-conventions": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.52.1.tgz", + "integrity": "sha512-MBYh+WcPPsN8YpRHRmK1Hsca9pVlyyKd4BxOC4SsgHACnl/bPp4Cri9hWhVm5+2tiQ9Zf4qSc1Jshw9tOLGWQA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.52.1", + "@opentelemetry/core": "1.25.1", + "@opentelemetry/resources": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.1.tgz", + "integrity": "sha512-9Mb7q5ioFL4E4dDrc4wC/A3NTHDat44v4I3p2pLPSxRvqUbDIQyMVr9uK+EU69+HWhlET1VaSrRzwdckWqY15Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1", + "@opentelemetry/resources": "1.25.1", + "lodash.merge": "^4.6.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.52.1.tgz", + "integrity": "sha512-uEG+gtEr6eKd8CVWeKMhH2olcCHM9dEK68pe0qE0be32BcCRsvYURhHaD1Srngh1SQcnQzZ4TP324euxqtBOJA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.52.1", + "@opentelemetry/core": "1.25.1", + "@opentelemetry/exporter-trace-otlp-grpc": "0.52.1", + "@opentelemetry/exporter-trace-otlp-http": "0.52.1", + "@opentelemetry/exporter-trace-otlp-proto": "0.52.1", + "@opentelemetry/exporter-zipkin": "1.25.1", + "@opentelemetry/instrumentation": "0.52.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/sdk-logs": "0.52.1", + "@opentelemetry/sdk-metrics": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1", + "@opentelemetry/sdk-trace-node": "1.25.1", + "@opentelemetry/semantic-conventions": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.25.1.tgz", + "integrity": "sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.25.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/semantic-conventions": "1.25.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.25.1.tgz", + "integrity": "sha512-nMcjFIKxnFqoez4gUmihdBrbpsEnAX/Xj16sGvZm+guceYE0NE00vLhpDVK6f3q8Q4VFI5xG8JjlXKMB/SkTTQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "1.25.1", + "@opentelemetry/core": "1.25.1", + "@opentelemetry/propagator-b3": "1.25.1", + "@opentelemetry/propagator-jaeger": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/dotenv": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", + "integrity": "sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", + "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", + "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/handlebars": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.1.0.tgz", + "integrity": "sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA==", + "deprecated": "This is a stub types definition. handlebars provides its own type definitions, so you do not need this installed.", + "license": "MIT", + "dependencies": { + "handlebars": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.10.tgz", + "integrity": "sha512-iAFpG6DokED3roLSP0K+ybeDdIX6Bc0Vd3mLW5uDqThPWtNos3E+EqOM11mPQHKzfWHqEBuLjIlsBQQ8CsISmQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==", + "license": "MIT" + }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concurrently": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.0.tgz", + "integrity": "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", + "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotprompt": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/dotprompt/-/dotprompt-1.1.1.tgz", + "integrity": "sha512-xll31JxDiE7FaF030t0Dx4EMSV60Qn/pONDn6Hs5bBBeEANbtqIu6fPfaAOoSNbF1Y9TK+pj9Xnvud7G7GHpaA==", + "license": "ISC", + "dependencies": { + "@types/handlebars": "^4.1.0", + "handlebars": "^4.7.8", + "yaml": "^2.7.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.3.tgz", + "integrity": "sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/fetch-blob/node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/genkit": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/genkit/-/genkit-1.16.0.tgz", + "integrity": "sha512-2zj8S3zfOz5zY7QsPyn/R4WfCfRIp1iV0w5r6YEnKI3FhA/avPqN9+fodnJcdv4jI5dnuVoaVgS6K8YpexmWCA==", + "license": "Apache-2.0", + "dependencies": { + "@genkit-ai/ai": "1.16.0", + "@genkit-ai/core": "1.16.0", + "uuid": "^10.0.0" + } + }, + "node_modules/genkitx-anthropic": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/genkitx-anthropic/-/genkitx-anthropic-0.23.1.tgz", + "integrity": "sha512-Fof8RaeGMtdts7+4ij5uF8qxNgQBQwB3TmiYIgW78PvYNlRy2S6xV70f84WSqLR41NCowgQZYfvCRmDo0GNosg==", + "license": "Apache-2.0", + "dependencies": { + "@anthropic-ai/sdk": "^0.39.0" + }, + "peerDependencies": { + "genkit": "^0.9.0 || ^1.0.0" + } + }, + "node_modules/genkitx-mcp": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/genkitx-mcp/-/genkitx-mcp-1.14.1.tgz", + "integrity": "sha512-Kx4Li182vASGYCLr8kEDtI1Huowim6eH8e94ZNcp8nSNoRh4ectuUFFY6lp2uMGsq37f/EUJrUB1Uou4saiINw==", + "license": "Apache-2.0", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.8.0" + }, + "peerDependencies": { + "@genkit-ai/core": "^1.14.1", + "genkit": "^1.14.1" + } + }, + "node_modules/genkitx-ollama": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/genkitx-ollama/-/genkitx-ollama-1.16.0.tgz", + "integrity": "sha512-56DQ1OSrunpeSBaRXfEqZA9pObC1wCobwFbOnnxKdzzLGcWjiLmjKreuO7/IVpjT/rKRzM32fwDOSnI54jqcgg==", + "license": "Apache-2.0", + "dependencies": { + "ollama": "^0.5.9" + }, + "peerDependencies": { + "genkit": "^1.16.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-in-the-middle": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.14.2.tgz", + "integrity": "sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "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.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ollama": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/ollama/-/ollama-0.5.17.tgz", + "integrity": "sha512-q5LmPtk6GLFouS+3aURIVl+qcAOPC4+Msmx7uBb3pd+fxI55WnGjmLZ0yijI/CYy79x0QPGx3BwC3u5zv9fBvQ==", + "license": "MIT", + "dependencies": { + "whatwg-fetch": "^3.6.20" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openai": { + "version": "4.104.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.122", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.122.tgz", + "integrity": "sha512-yzegtT82dwTNEe/9y+CM8cgb42WrUfMMCg2QqSddzO1J6uPmBD7qKCZ7dOHZP2Yrpm/kb0eqdNMn2MUyEiqBmA==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/protobufjs": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.3.tgz", + "integrity": "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "license": "BSD-2-Clause" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node-dev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", + "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^10.4.0", + "tsconfig": "^7.0.0" + }, + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-templates": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/uri-templates/-/uri-templates-0.2.0.tgz", + "integrity": "sha512-EWkjYEN0L6KOfEoOH6Wj4ghQqU7eBZMJqRHQnxQAq+dSEzRPClkWjf8557HkWQXF6BrAUoLSAyy9i3RVTliaNg==", + "license": "http://geraintluff.github.io/tv4/LICENSE.txt" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + } + } +} diff --git a/genkit/package.json b/genkit/package.json new file mode 100644 index 00000000..93caceef --- /dev/null +++ b/genkit/package.json @@ -0,0 +1,44 @@ +{ + "name": "brc-analytics-genkit", + "version": "1.0.0", + "description": "GenKit backend for BRC Analytics", + "main": "dist/index.js", + "type": "commonjs", + "scripts": { + "build": "tsc", + "start": "node dist/server.js", + "dev": "ts-node-dev --respawn src/server.ts", + "lint": "tsc --noEmit" + }, + "keywords": [ + "brc", + "analytics", + "genkit" + ], + "author": "", + "license": "MIT", + "dependencies": { + "@genkit-ai/compat-oai": "^1.15.5", + "@genkit-ai/googleai": "^1.15.5", + "@types/multer": "^2.0.0", + "axios": "^1.11.0", + "dotenv": "^17.2.1", + "express": "^5.1.0", + "genkit": "^1.16.0", + "genkitx-anthropic": "^0.23.1", + "genkitx-mcp": "^1.14.1", + "genkitx-ollama": "^1.15.5", + "multer": "^2.0.2" + }, + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/dotenv": "^6.1.1", + "@types/express": "^5.0.3", + "@types/node": "^20.11.0", + "concurrently": "^9.2.0", + "cors": "^2.8.5", + "ts-node": "^10.9.2", + "ts-node-dev": "^2.0.0", + "typescript": "^5.3.3" + } +} diff --git a/genkit/src/ai.ts b/genkit/src/ai.ts new file mode 100644 index 00000000..6661bdac --- /dev/null +++ b/genkit/src/ai.ts @@ -0,0 +1,160 @@ +import { genkit } from "genkit"; +import { googleAI } from "@genkit-ai/googleai"; +import { logger } from "@genkit-ai/core/logging"; +import dotenv from "dotenv"; +import { mcpClient } from "genkitx-mcp"; + +// Import providers based on installed packages +import { anthropic, claude35Sonnet, claude35Haiku } from "genkitx-anthropic"; +import { ollama } from "genkitx-ollama"; +import { openAI } from "@genkit-ai/compat-oai/openai"; + +// Load environment variables from .env file +dotenv.config(); + +// Helper function to configure the model based on environment variables +// eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do +function configureModel(): any { + const provider = process.env.MODEL_PROVIDER || "google"; + const modelName = process.env.MODEL_NAME || "gemini-2.5-flash"; + const temperature = parseFloat(process.env.MODEL_TEMPERATURE || "0.7"); + + switch (provider.toLowerCase()) { + case "google": + // Configure Google AI with API key if provided + if (process.env.GOOGLE_API_KEY) { + return googleAI.model(modelName, { + apiKey: process.env.GOOGLE_API_KEY, + temperature, + }); + } else { + return googleAI.model(modelName, { temperature }); + } + + case "openai": + if (!process.env.OPENAI_API_KEY) { + throw new Error( + "OPENAI_API_KEY is required when using OpenAI provider" + ); + } + return openAI.model(modelName, { + apiKey: process.env.OPENAI_API_KEY, + temperature, + }); + + case "anthropic": + if (!process.env.ANTHROPIC_API_KEY) { + throw new Error( + "ANTHROPIC_API_KEY is required when using Anthropic provider" + ); + } + + switch (modelName) { + case "claude-3-5-sonnet": + return claude35Sonnet; + case "claude-3-5-haiku": + return claude35Haiku; + default: + logger.warn( + `Unknown Anthropic model '${modelName}', falling back to claude-3-5-sonnet` + ); + return claude35Sonnet; + } + + case "ollama": { + const ollamaUrl = process.env.OLLAMA_URL || "http://localhost:11434"; + return ollama.model(modelName, { + baseURL: ollamaUrl, + temperature, + }); + } + + default: + logger.warn(`Unknown provider '${provider}', falling back to Google AI`); + return googleAI.model(modelName, { temperature }); + } +} + +// Helper function to configure model provider plugins +// eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do +function configureProviderPlugins(): any { + const provider = process.env.MODEL_PROVIDER || "google"; + + switch (provider.toLowerCase()) { + case "google": + return googleAI( + process.env.GOOGLE_API_KEY + ? { apiKey: process.env.GOOGLE_API_KEY } + : undefined + ); + + case "openai": + if (!process.env.OPENAI_API_KEY) { + throw new Error( + "OPENAI_API_KEY is required when using OpenAI provider" + ); + } + return openAI({ apiKey: process.env.OPENAI_API_KEY }); + + case "anthropic": + if (!process.env.ANTHROPIC_API_KEY) { + throw new Error( + "ANTHROPIC_API_KEY is required when using Anthropic provider" + ); + } + return anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); + + case "ollama": { + const ollamaUrl = process.env.OLLAMA_URL || "http://localhost:11434"; + return ollama({ serverAddress: ollamaUrl }); + } + + default: + logger.warn(`Unknown provider '${provider}', falling back to Google AI`); + return googleAI( + process.env.GOOGLE_API_KEY + ? { apiKey: process.env.GOOGLE_API_KEY } + : undefined + ); + } +} + +// Get model configuration +const modelConfig = ((): ReturnType => { + try { + return configureModel(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } catch (error: any) { + // Type assertion for error + logger.error( + `Error configuring model: ${error?.message || "Unknown error"}` + ); + // Fall back to Google AI with default settings + return googleAI.model("gemini-2.5-flash", { temperature: 0.7 }); + } +})(); + +// Configure Galaxy MCP client +export const galaxyMcpClient = mcpClient({ + name: "galaxy", + serverProcess: { + args: ["galaxy-mcp"], + command: "uvx", + cwd: + process.env.GALAXY_MCP_PATH || + "/home/dcallan-adm/Documents/brc-analytics/galaxy-mcp", + }, +}); + +// Create the AI instance with the configured model and MCP client +export const ai = genkit({ + model: modelConfig, + plugins: [ + // Configure your model provider based on environment variables + configureProviderPlugins(), + galaxyMcpClient, + ], +}); + +// Set logging level (useful for debugging) +logger.setLogLevel("debug"); diff --git a/genkit/src/dataStore.ts b/genkit/src/dataStore.ts new file mode 100644 index 00000000..919d67c5 --- /dev/null +++ b/genkit/src/dataStore.ts @@ -0,0 +1,277 @@ +import fs from "fs"; +import path from "path"; +import { Organism, Assembly, Workflow, Outbreak } from "./types"; + +/** + * DataStore class for accessing BRC Analytics catalog data + * + * @class + * @property {string} basePath - The base path for the catalog data + * @property {Organism[]} organisms - The organisms data + * @property {Assembly[]} assemblies - The assemblies data + * @property {Workflow[]} workflows - The workflows data + * @property {Outbreak[]} outbreaks - The outbreaks data + * + * @returns {DataStore} A new DataStore instance + */ +export class DataStore { + private basePath: string; + private organisms: Organism[] | null = null; + private assemblies: Assembly[] | null = null; + private workflows: Workflow[] | null = null; + private outbreaks: Outbreak[] | null = null; + + constructor(basePath: string) { + this.basePath = basePath; + // Ensure the directory exists + if (!fs.existsSync(basePath)) { + throw new Error(`Catalog output directory not found: ${basePath}`); + } + } + + /** + * Get all organisms + * + * @returns {Promise} A promise that resolves to an array of organisms + */ + async getOrganisms(): Promise { + if (!this.organisms) { + try { + const filePath = path.join(this.basePath, "organisms.json"); + const data = fs.readFileSync(filePath, "utf8"); + this.organisms = JSON.parse(data) as Organism[]; + } catch (error) { + console.error("Error loading organisms:", error); + throw new Error("Failed to load organisms data"); + } + } + return this.organisms; + } + + /** + * Get organism by taxonomy ID + * + * @param {string} taxonomyId - The taxonomy ID of the organism + * + * @returns {Promise} A promise that resolves to an organism or null + */ + async getOrganismByTaxonomyId(taxonomyId: string): Promise { + const organisms = await this.getOrganisms(); + return ( + organisms.find( + (org) => + org.assemblyTaxonomyIds && + Array.isArray(org.assemblyTaxonomyIds) && + org.assemblyTaxonomyIds.includes(taxonomyId) + ) || null + ); + } + + /** + * Get all assemblies + * + * @returns {Promise} A promise that resolves to an array of assemblies + */ + async getAssemblies(): Promise { + if (!this.assemblies) { + try { + const filePath = path.join(this.basePath, "assemblies.json"); + const data = fs.readFileSync(filePath, "utf8"); + this.assemblies = JSON.parse(data) as Assembly[]; + } catch (error) { + console.error("Error loading assemblies:", error); + throw new Error("Failed to load assemblies data"); + } + } + return this.assemblies; + } + + /** + * Get assembly by accession + * + * @param {string} accession - The accession of the assembly + * + * @returns {Promise} A promise that resolves to an assembly or null + */ + async getAssemblyByAccession(accession: string): Promise { + const assemblies = await this.getAssemblies(); + return ( + assemblies.find((assembly) => assembly.accession === accession) || null + ); + } + + /** + * Get assemblies by taxonomy ID + * + * @param {string} taxonomyId - The taxonomy ID of the assemblies + * + * @returns {Promise} A promise that resolves to an array of assemblies + */ + async getAssembliesByTaxonomyId(taxonomyId: string): Promise { + const assemblies = await this.getAssemblies(); + return assemblies.filter( + (assembly) => + assembly.ncbiTaxonomyId === taxonomyId || + (assembly.lineageTaxonomyIds && + Array.isArray(assembly.lineageTaxonomyIds) && + assembly.lineageTaxonomyIds.includes(taxonomyId)) + ); + } + + /** + * Get all workflows + * + * @returns {Promise} A promise that resolves to an array of workflows + */ + async getWorkflows(): Promise { + if (!this.workflows) { + try { + const filePath = path.join(this.basePath, "workflows.json"); + const data = fs.readFileSync(filePath, "utf8"); + const categories = JSON.parse(data) as Array<{ + category: string; + description: string; + name: string; + workflows?: Array<{ + iwcId?: string; + parameters?: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any -- what would marius do + workflowDescription?: string; + workflowName?: string; + }>; + }>; + + // Transform the categories into individual workflows with proper structure + this.workflows = []; + + categories.forEach((category, categoryIndex) => { + // Create a workflow for the category itself + const categoryWorkflow: Workflow = { + description: category.description || "", + id: `category-${categoryIndex + 1}`, + name: category.name || "Unnamed Category", + parameters: [], + steps: [], + tags: [ + category.category + ? category.category.toLowerCase() + : "uncategorized", + ], + version: "1.0.0", + }; + + if (this.workflows) { + // Check if this.workflows is not null + this.workflows.push(categoryWorkflow); + } + + // Add individual workflows from this category if they exist + if (Array.isArray(category.workflows)) { + category.workflows.forEach((workflow, workflowIndex) => { + if (this.workflows) { + // Check if this.workflows is not null + this.workflows.push({ + description: workflow.workflowDescription || "", + id: + workflow.iwcId || + `workflow-${categoryIndex + 1}-${workflowIndex + 1}`, + name: workflow.workflowName || "Unnamed Workflow", + parameters: workflow.parameters || [], + steps: [], + tags: [ + category.category + ? category.category.toLowerCase() + : "uncategorized", + ], + version: "1.0.0", + }); + } + }); + } + }); + } catch (error) { + console.error("Error loading workflows:", error); + throw new Error("Failed to load workflows data"); + } + } + return this.workflows; + } + + /** + * Get workflow by ID + * + * @param {string} id - The ID of the workflow + * + * @returns {Promise} A promise that resolves to a workflow or null + */ + async getWorkflowById(id: string): Promise { + const workflows = await this.getWorkflows(); + return workflows.find((workflow) => workflow.id === id) || null; + } + + /** + * Get workflows by tag + * + * @param {string} tag - The tag of the workflows + * + * @returns {Promise} A promise that resolves to an array of workflows + */ + async getWorkflowsByTag(tag: string): Promise { + const workflows = await this.getWorkflows(); + return workflows.filter( + (workflow) => + workflow.tags && + Array.isArray(workflow.tags) && + workflow.tags.includes(tag) + ); + } + + /** + * Get all outbreaks + * + * @returns {Promise} A promise that resolves to an array of outbreaks + */ + async getOutbreaks(): Promise { + if (!this.outbreaks) { + try { + const filePath = path.join(this.basePath, "outbreaks.json"); + const data = fs.readFileSync(filePath, "utf8"); + this.outbreaks = JSON.parse(data) as Outbreak[]; + } catch (error) { + console.error("Error loading outbreaks:", error); + throw new Error("Failed to load outbreaks data"); + } + } + return this.outbreaks; + } + + /** + * Get outbreak by ID + * + * @param {string} id - The ID of the outbreak + * + * @returns {Promise} A promise that resolves to an outbreak or null + */ + async getOutbreakById(id: string): Promise { + const outbreaks = await this.getOutbreaks(); + return outbreaks.find((outbreak) => outbreak.id === id) || null; + } + + /** + * Get outbreak by taxonomy ID + * + * @param {string} taxonomyId - The taxonomy ID of the outbreak + * + * @returns {Promise} A promise that resolves to an outbreak or null + */ + async getOutbreakByTaxonomyId(taxonomyId: string): Promise { + const outbreaks = await this.getOutbreaks(); + return ( + outbreaks.find((outbreak) => outbreak.taxonomyId === taxonomyId) || null + ); + } +} + +// Create a singleton instance +export const dataStore = new DataStore( + process.env.CATALOG_OUTPUT_PATH || "../catalog/output" +); diff --git a/genkit/src/galaxyTools.ts b/genkit/src/galaxyTools.ts new file mode 100644 index 00000000..e8fa841d --- /dev/null +++ b/genkit/src/galaxyTools.ts @@ -0,0 +1,1686 @@ +import { z } from "genkit"; +import { logger } from "@genkit-ai/core/logging"; +import { ai } from "./ai"; +import { galaxyMcpClient } from "./ai"; + +/** + * Tool to get Galaxy server information + */ +export const getGalaxyServerInfoTool = ai.defineTool( + { + description: "Get information about the connected Galaxy server", + inputSchema: z.object({}), + name: "getGalaxyServerInfo", + outputSchema: z + .object({ + config: z.record(z.unknown()).describe("Server configuration"), + url: z.string().describe("The URL of the Galaxy server"), + version: z + .object({ + version_major: z.string().optional(), + version_minor: z.string().optional(), + }) + .describe("Version information"), + }) + .describe("Galaxy server information"), + }, + async (): Promise<{ + config: Record; + url: string; + version: { version_major?: string; version_minor?: string }; + }> => { + try { + // Use the Galaxy MCP client to get server information + const response = (await galaxyMcpClient.call( + "get_server_info", + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + {} as any + )) as unknown as { + config?: Record; + url?: string; + version?: { version_major?: string; version_minor?: string }; + }; + + // Create a properly typed object from the response + const serverInfo = { + config: response?.config || {}, + url: String(response?.url || ""), + version: { + version_major: response?.version?.version_major + ? String(response.version.version_major) + : undefined, + version_minor: response?.version?.version_minor + ? String(response.version.version_minor) + : undefined, + }, + }; + + return serverInfo; + } catch (error) { + logger.error("Error getting Galaxy server info:", error); + throw new Error( + `Failed to get Galaxy server info: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get Galaxy histories + */ +export const getGalaxyHistoriesTool = ai.defineTool( + { + description: "Get a list of histories from the Galaxy server", + inputSchema: z.object({ + limit: z + .number() + .optional() + .describe("Maximum number of histories to return (optional)"), + offset: z + .number() + .optional() + .describe("Offset for pagination (optional)"), + }), + name: "getGalaxyHistories", + outputSchema: z + .object({ + histories: z.array( + z.object({ + deleted: z.boolean().describe("Whether the history is deleted"), + id: z.string().describe("History ID"), + name: z.string().describe("History name"), + purged: z.boolean().describe("Whether the history is purged"), + tags: z.array(z.string()).describe("History tags"), + update_time: z.string().describe("Last update time"), + }) + ), + total: z.number().describe("Total number of histories"), + }) + .describe("Galaxy histories information"), + }, + async (input: { + limit?: number; + offset?: number; + }): Promise<{ + histories: Array<{ + deleted: boolean; + id: string; + name: string; + purged: boolean; + tags: string[]; + update_time: string; + }>; + total: number; + }> => { + try { + // Use the Galaxy MCP client to get histories + const response = (await galaxyMcpClient.call("get_histories", { + limit: input.limit, + offset: input.offset, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + histories?: Array<{ + deleted?: boolean; + id?: string; + name?: string; + purged?: boolean; + tags?: string[]; + update_time?: string; + }>; + total?: number; + }; + + // Process the response to match our schema + const histories = (response.histories || []).map((history) => ({ + deleted: Boolean(history.deleted), + id: String(history.id || ""), + name: String(history.name || ""), + purged: Boolean(history.purged), + tags: Array.isArray(history.tags) ? history.tags.map(String) : [], + update_time: String(history.update_time || ""), + })); + + return { + histories, + total: Number(response.total || 0), + }; + } catch (error) { + logger.error("Error getting Galaxy histories:", error); + throw new Error( + `Failed to get Galaxy histories: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get Galaxy history details + */ +export const getHistoryDetailsTool = ai.defineTool( + { + description: + "Get detailed information about a specific Galaxy history, including datasets", + inputSchema: z.object({ + history_id: z.string().describe("ID of the history to get details for"), + }), + name: "getHistoryDetails", + outputSchema: z + .object({ + datasets: z.array( + z.object({ + data_type: z.string().describe("Dataset data type"), + deleted: z.boolean().describe("Whether the dataset is deleted"), + file_ext: z.string().describe("Dataset file extension"), + file_size: z.number().describe("Dataset file size in bytes"), + history_id: z.string().describe("History ID"), + id: z.string().describe("Dataset ID"), + misc_blurb: z.string().describe("Miscellaneous dataset blurb"), + misc_info: z.string().describe("Miscellaneous dataset information"), + name: z.string().describe("Dataset name"), + purged: z.boolean().describe("Whether the dataset is purged"), + state: z.string().describe("Dataset state"), + tags: z.array(z.string()).describe("Dataset tags"), + visible: z.boolean().describe("Whether the dataset is visible"), + }) + ), + }) + .describe("Galaxy history details"), + }, + async (input: { + history_id: string; + }): Promise<{ + datasets: Array<{ + data_type: string; + deleted: boolean; + file_ext: string; + file_size: number; + history_id: string; + id: string; + misc_blurb: string; + misc_info: string; + name: string; + purged: boolean; + state: string; + tags: string[]; + visible: boolean; + }>; + deleted: boolean; + id: string; + name: string; + purged: boolean; + tags: string[]; + update_time: string; + }> => { + try { + // Use the Galaxy MCP client to get history details + const response = (await galaxyMcpClient.call("get_history_details", { + history_id: input.history_id, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + datasets?: Array<{ + data_type?: string; + deleted?: boolean; + file_ext?: string; + file_size?: number; + history_id?: string; + id?: string; + misc_blurb?: string; + misc_info?: string; + name?: string; + purged?: boolean; + state?: string; + tags?: string[]; + visible?: boolean; + }>; + deleted?: boolean; + id?: string; + name?: string; + purged?: boolean; + tags?: string[]; + update_time?: string; + }; + + // Process the response to match our schema + const datasets = (response.datasets || []).map((dataset) => ({ + data_type: String(dataset.data_type || ""), + deleted: Boolean(dataset.deleted), + file_ext: String(dataset.file_ext || ""), + file_size: Number(dataset.file_size || 0), + history_id: String(dataset.history_id || ""), + id: String(dataset.id || ""), + misc_blurb: String(dataset.misc_blurb || ""), + misc_info: String(dataset.misc_info || ""), + name: String(dataset.name || ""), + purged: Boolean(dataset.purged), + state: String(dataset.state || ""), + tags: Array.isArray(dataset.tags) ? dataset.tags.map(String) : [], + visible: Boolean(dataset.visible), + })); + + return { + datasets, + deleted: Boolean(response.deleted), + id: String(response.id || ""), + name: String(response.name || ""), + purged: Boolean(response.purged), + tags: Array.isArray(response.tags) ? response.tags.map(String) : [], + update_time: String(response.update_time || ""), + }; + } catch (error) { + logger.error("Error getting Galaxy history details:", error); + throw new Error( + `Failed to get Galaxy history details: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to search Galaxy tools + */ +export const searchGalaxyToolsTool = ai.defineTool( + { + description: "Search for tools in the Galaxy server by name", + inputSchema: z.object({ + query: z + .string() + .describe("Search query for finding tools by name or description"), + }), + name: "searchGalaxyTools", + outputSchema: z + .object({ + tools: z.array( + z.object({ + config_file: z.string().describe("Tool configuration file path"), + description: z.string().describe("Tool description"), + id: z.string().describe("Tool ID"), + name: z.string().describe("Tool name"), + panel_section_name: z.string().describe("Tool panel section name"), + version: z.string().describe("Tool version"), + }) + ), + total: z.number().describe("Total number of tools found"), + }) + .describe("Galaxy tools search results"), + }, + async (input: { + query: string; + }): Promise<{ + tools: Array<{ + config_file: string; + description: string; + id: string; + name: string; + panel_section_name: string; + version: string; + }>; + total: number; + }> => { + try { + // Use the Galaxy MCP client to search for tools + const response = (await galaxyMcpClient.call("search_tools", { + query: input.query, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + tools?: Array<{ + config_file?: string; + description?: string; + id?: string; + name?: string; + panel_section_name?: string; + version?: string; + }>; + total?: number; + }; + + // Process the response to match our schema + const tools = (response.tools || []).map((tool) => ({ + config_file: String(tool.config_file || ""), + description: String(tool.description || ""), + id: String(tool.id || ""), + name: String(tool.name || ""), + panel_section_name: String(tool.panel_section_name || ""), + version: String(tool.version || ""), + })); + + return { + tools, + total: Number(response.total || 0), + }; + } catch (error) { + logger.error("Error searching Galaxy tools:", error); + throw new Error( + `Failed to search Galaxy tools: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to create a new Galaxy history + */ +export const createGalaxyHistoryTool = ai.defineTool( + { + description: "Create a new history in the Galaxy server", + inputSchema: z.object({ + name: z.string().describe("Name for the new history"), + }), + name: "createGalaxyHistory", + outputSchema: z + .object({ + deleted: z.boolean().describe("Whether the history is deleted"), + id: z.string().describe("ID of the created history"), + name: z.string().describe("Name of the created history"), + purged: z.boolean().describe("Whether the history is purged"), + tags: z.array(z.string()).describe("History tags"), + update_time: z.string().describe("Last update time"), + }) + .describe("Created Galaxy history information"), + }, + async (input: { + name: string; + }): Promise<{ + deleted: boolean; + id: string; + name: string; + purged: boolean; + tags: string[]; + update_time: string; + }> => { + try { + // Use the Galaxy MCP client to create a new history + const response = (await galaxyMcpClient.call("create_history", { + name: input.name, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + deleted?: boolean; + id?: string; + name?: string; + purged?: boolean; + tags?: string[]; + update_time?: string; + }; + + // Process the response to match our schema + return { + deleted: Boolean(response.deleted), + id: String(response.id || ""), + name: String(response.name || ""), + purged: Boolean(response.purged), + tags: Array.isArray(response.tags) ? response.tags.map(String) : [], + update_time: String(response.update_time || ""), + }; + } catch (error) { + logger.error("Error creating Galaxy history:", error); + throw new Error( + `Failed to create Galaxy history: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to run a Galaxy tool + */ +export const runGalaxyToolTool = ai.defineTool( + { + description: "Run a tool in the Galaxy server", + inputSchema: z.object({ + history_id: z.string().describe("ID of the history to run the tool in"), + inputs: z + .record(z.string(), z.unknown()) + .describe("Input parameters for the tool"), + tool_id: z.string().describe("ID of the tool to run"), + }), + name: "runGalaxyTool", + outputSchema: z + .object({ + history_id: z.string().describe("ID of the history"), + job_id: z.string().describe("ID of the created job"), + output_ids: z.array(z.string()).describe("IDs of the output datasets"), + tool_id: z.string().describe("ID of the tool"), + }) + .describe("Galaxy tool run information"), + }, + async (input: { + history_id: string; + inputs: Record; + tool_id: string; + }): Promise<{ + history_id: string; + job_id: string; + output_ids: string[]; + tool_id: string; + }> => { + try { + // Use the Galaxy MCP client to run a tool + const response = (await galaxyMcpClient.call("run_tool", { + history_id: input.history_id, + inputs: input.inputs, + tool_id: input.tool_id, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + history_id?: string; + job_id?: string; + output_ids?: string[]; + tool_id?: string; + }; + + // Process the response to match our schema + return { + history_id: String(response.history_id || ""), + job_id: String(response.job_id || ""), + output_ids: Array.isArray(response.output_ids) + ? response.output_ids.map(String) + : [], + tool_id: String(response.tool_id || ""), + }; + } catch (error) { + logger.error("Error running Galaxy tool:", error); + throw new Error( + `Failed to run Galaxy tool: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get IWC workflows + */ +export const getIwcWorkflowsTool = ai.defineTool( + { + description: "Get workflows from the Interoperable Workflow Catalog (IWC)", + inputSchema: z.object({ + limit: z + .number() + .optional() + .describe("Optional limit on the number of workflows to return"), + offset: z.number().optional().describe("Optional offset for pagination"), + }), + name: "getIwcWorkflows", + outputSchema: z + .object({ + total: z.number().describe("Total number of workflows"), + workflows: z.array( + z.object({ + authors: z.array(z.string()).describe("Authors of the workflow"), + description: z.string().describe("Description of the workflow"), + name: z.string().describe("Name of the workflow"), + trs_id: z.string().describe("TRS ID of the workflow"), + version: z.string().describe("Version of the workflow"), + }) + ), + }) + .describe("IWC workflows information"), + }, + async (input: { + limit?: number; + offset?: number; + }): Promise<{ + total: number; + workflows: Array<{ + authors: string[]; + description: string; + name: string; + trs_id: string; + version: string; + }>; + }> => { + try { + // Use the Galaxy MCP client to get IWC workflows + const response = (await galaxyMcpClient.call("get_iwc_workflows", { + limit: input.limit, + offset: input.offset, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + total?: number; + workflows?: Array<{ + authors?: string[]; + description?: string; + name?: string; + tags?: string[]; + trs_id?: string; + version?: string; + }>; + }; + + // Process the response to match our schema + const workflows = (response.workflows || []).map((workflow) => ({ + authors: Array.isArray(workflow.authors) + ? workflow.authors.map(String) + : [], + description: String(workflow.description || ""), + name: String(workflow.name || ""), + trs_id: String(workflow.trs_id || ""), + version: String(workflow.version || ""), + })); + + return { + total: Number(response.total || 0), + workflows, + }; + } catch (error) { + logger.error("Error getting IWC workflows:", error); + throw new Error( + `Failed to get IWC workflows: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to search for workflows in the Interoperable Workflow Catalog (IWC) + */ +export const searchIwcWorkflowsTool = ai.defineTool( + { + description: + "Search for workflows in the Interoperable Workflow Catalog (IWC)", + inputSchema: z.object({ + query: z.string().describe("Search query"), + }), + name: "searchIwcWorkflows", + outputSchema: z + .object({ + count: z.number().describe("Total number of matching workflows"), + workflows: z + .array( + z.object({ + authors: z + .array(z.string()) + .optional() + .describe("Workflow authors"), + description: z + .string() + .optional() + .describe("Workflow description"), + name: z.string().describe("Workflow name"), + tags: z.array(z.string()).optional().describe("Workflow tags"), + trs_id: z.string().describe("TRS ID of the workflow"), + }) + ) + .describe("List of matching IWC workflows"), + }) + .describe("IWC workflow search results"), + }, + async (input: { + query: string; + }): Promise<{ + count: number; + workflows: Array<{ + authors?: string[]; + description?: string; + name: string; + tags?: string[]; + trs_id: string; + }>; + }> => { + try { + // Use the Galaxy MCP client to search for IWC workflows + const response = (await galaxyMcpClient.call("search_iwc_workflows", { + query: input.query, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + count?: number; + workflows?: Array<{ + authors?: string[]; + description?: string; + name?: string; + tags?: string[]; + trs_id?: string; + }>; + }; + + // Process the response to match our schema + const workflows = (response.workflows || []).map((workflow) => ({ + authors: workflow.authors, + description: workflow.description, + name: String(workflow.name || ""), + tags: workflow.tags, + trs_id: String(workflow.trs_id || ""), + })); + + return { + count: Number(response.count || 0), + workflows, + }; + } catch (error) { + logger.error("Error searching IWC workflows:", error); + throw new Error( + `Failed to search IWC workflows: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to import a workflow from the Interoperable Workflow Catalog (IWC) to Galaxy + */ +export const importWorkflowFromIwcTool = ai.defineTool( + { + description: + "Import a workflow from the Interoperable Workflow Catalog (IWC) to Galaxy", + inputSchema: z.object({ + trs_id: z.string().describe("TRS ID of the workflow to import"), + }), + name: "importWorkflowFromIwc", + outputSchema: z + .object({ + id: z.string().describe("ID of the imported workflow"), + name: z.string().describe("Name of the imported workflow"), + tags: z + .array(z.string()) + .optional() + .describe("Tags of the imported workflow"), + }) + .describe("Imported workflow details"), + }, + async (input: { + trs_id: string; + }): Promise<{ + id: string; + name: string; + tags?: string[]; + }> => { + try { + // Use the Galaxy MCP client to import a workflow from IWC + const response = (await galaxyMcpClient.call("import_workflow_from_iwc", { + trs_id: input.trs_id, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + id?: string; + name?: string; + tags?: string[]; + }; + + // Process the response to match our schema + const result = { + id: String(response?.id || ""), + name: String(response?.name || ""), + tags: Array.isArray(response?.tags) + ? response.tags.map(String) + : undefined, + }; + + return result; + } catch (error) { + logger.error("Error importing workflow from IWC:", error); + throw new Error( + `Failed to import workflow from IWC: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get detailed information about a specific Galaxy job + */ +export const getGalaxyJobDetailsTool = ai.defineTool( + { + description: "Get detailed information about a specific Galaxy job", + inputSchema: z.object({ + job_id: z.string().describe("ID of the job to get details for"), + }), + name: "getGalaxyJobDetails", + outputSchema: z + .object({ + job: z + .object({ + create_time: z + .string() + .optional() + .describe("Time when the job was created"), + exit_code: z.number().optional().describe("Exit code of the job"), + history_id: z + .string() + .optional() + .describe("ID of the history containing this job"), + id: z.string().describe("The unique identifier of the job"), + state: z + .string() + .describe( + 'Current state of the job (e.g., "new", "running", "ok", "error")' + ), + tool_id: z.string().describe("ID of the tool that was run"), + tool_version: z + .string() + .optional() + .describe("Version of the tool that was run"), + update_time: z + .string() + .optional() + .describe("Time when the job was last updated"), + }) + .describe("Job information"), + }) + .describe("Galaxy job details"), + }, + async (input: { + job_id: string; + }): Promise<{ + job: { + create_time?: string; + exit_code?: number; + history_id?: string; + id: string; + state: string; + tool_id: string; + tool_version?: string; + update_time?: string; + }; + }> => { + try { + // Use the Galaxy MCP client to get job details + const response = (await galaxyMcpClient.call("get_job_details", { + job_id: input.job_id, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + job?: { + create_time?: string; + exit_code?: number; + history_id?: string; + id?: string; + state?: string; + tool_id?: string; + tool_version?: string; + update_time?: string; + }; + }; + + // Process the response to match our schema + const result = { + job: { + create_time: response?.job?.create_time + ? String(response.job.create_time) + : undefined, + exit_code: + typeof response?.job?.exit_code === "number" + ? response.job.exit_code + : undefined, + history_id: response?.job?.history_id + ? String(response.job.history_id) + : undefined, + id: String(response?.job?.id || ""), + state: String(response?.job?.state || ""), + tool_id: String(response?.job?.tool_id || ""), + tool_version: response?.job?.tool_version + ? String(response.job.tool_version) + : undefined, + update_time: response?.job?.update_time + ? String(response.job.update_time) + : undefined, + }, + }; + + return result; + } catch (error) { + logger.error("Error getting Galaxy job details:", error); + throw new Error( + `Failed to get Galaxy job details: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to upload a local file to Galaxy + */ +export const uploadFileToGalaxyTool = ai.defineTool( + { + description: "Upload a local file to Galaxy", + inputSchema: z.object({ + history_id: z + .string() + .optional() + .describe("Target history ID (optional)"), + path: z.string().describe("Path to local file to upload"), + }), + name: "uploadFileToGalaxy", + outputSchema: z + .object({ + file_ext: z + .string() + .optional() + .describe("File extension of the uploaded file"), + file_size: z + .number() + .optional() + .describe("Size of the uploaded file in bytes"), + history_id: z + .string() + .describe("ID of the history containing the uploaded dataset"), + id: z.string().describe("ID of the uploaded dataset"), + name: z.string().describe("Name of the uploaded dataset"), + state: z.string().describe("State of the uploaded dataset"), + }) + .describe("Upload status"), + }, + async (input: { + history_id?: string; + path: string; + }): Promise<{ + file_ext?: string; + file_size?: number; + history_id: string; + id: string; + name: string; + state: string; + }> => { + try { + // Use the Galaxy MCP client to upload a file + const response = (await galaxyMcpClient.call("upload_file", { + history_id: input.history_id, + path: input.path, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + file_ext?: string; + file_size?: number; + history_id?: string; + id?: string; + name?: string; + state?: string; + }; + + // Process the response to match our schema + const result = { + file_ext: response?.file_ext ? String(response.file_ext) : undefined, + file_size: + typeof response?.file_size === "number" + ? response.file_size + : undefined, + history_id: String(response?.history_id || ""), + id: String(response?.id || ""), + name: String(response?.name || ""), + state: String(response?.state || ""), + }; + + return result; + } catch (error) { + logger.error("Error uploading file to Galaxy:", error); + throw new Error( + `Failed to upload file to Galaxy: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to filter Galaxy tools by dataset type + */ +export const filterToolsByDatasetTool = ai.defineTool( + { + description: + "Filter Galaxy tools that are potentially suitable for a given dataset type", + inputSchema: z.object({ + dataset_type: z + .array(z.string()) + .describe( + 'A list of keywords or phrases describing the dataset type (e.g., ["csv", "tabular"])' + ), + }), + name: "filterToolsByDataset", + outputSchema: z + .object({ + count: z.number().describe("Total number of tools found"), + tools: z + .array( + z.object({ + description: z + .string() + .optional() + .describe("The description of the tool"), + id: z.string().describe("The unique identifier of the tool"), + name: z.string().describe("The name of the tool"), + panel_section_name: z + .string() + .optional() + .describe("The panel section where the tool appears"), + version: z + .string() + .optional() + .describe("The version of the tool"), + }) + ) + .describe("List of tools suitable for the dataset type"), + }) + .describe("Galaxy tools filtered by dataset type"), + }, + async (input: { + dataset_type: string[]; + }): Promise<{ + count: number; + tools: Array<{ + description?: string; + id: string; + name: string; + panel_section_name?: string; + version?: string; + }>; + }> => { + try { + // Use the Galaxy MCP client to filter tools by dataset type + const response = (await galaxyMcpClient.call("filter_tools_by_dataset", { + dataset_type: input.dataset_type, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + count?: number; + tools?: Array<{ + description?: string; + id?: string; + name?: string; + panel_section_name?: string; + version?: string; + }>; + }; + + // Process the response to match our schema + const result = { + count: typeof response?.count === "number" ? response.count : 0, + tools: Array.isArray(response?.tools) + ? response.tools.map((tool) => ({ + description: tool?.description + ? String(tool.description) + : undefined, + id: String(tool?.id || ""), + name: String(tool?.name || ""), + panel_section_name: tool?.panel_section_name + ? String(tool.panel_section_name) + : undefined, + version: tool?.version ? String(tool.version) : undefined, + })) + : [], + }; + + return result; + } catch (error) { + logger.error("Error filtering Galaxy tools by dataset type:", error); + throw new Error( + `Failed to filter Galaxy tools by dataset type: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get Galaxy workflow invocations + */ +export const getGalaxyInvocationsTool = ai.defineTool( + { + description: "View workflow invocations in Galaxy", + inputSchema: z.object({ + history_id: z + .string() + .optional() + .describe("Filter invocations by history ID (optional)"), + invocation_id: z + .string() + .optional() + .describe("Specific invocation ID to view details (optional)"), + limit: z + .number() + .optional() + .describe("Maximum number of invocations to return (optional)"), + step_details: z + .boolean() + .optional() + .default(false) + .describe( + 'Include details on individual steps (only if view is "element")' + ), + view: z + .enum(["element", "collection"]) + .optional() + .default("collection") + .describe("Level of detail to return (default: collection)"), + workflow_id: z + .string() + .optional() + .describe("Filter invocations by workflow ID (optional)"), + }), + name: "getGalaxyInvocations", + outputSchema: z + .object({ + invocation: z + .object({ + create_time: z + .string() + .optional() + .describe("Time when the invocation was created"), + history_id: z + .string() + .describe("ID of the history where the invocation was run"), + id: z.string().describe("The unique identifier of the invocation"), + state: z.string().describe("Current state of the invocation"), + steps: z + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + .array(z.any()) + .optional() + .describe("Steps in the invocation (if step_details is true)"), + update_time: z + .string() + .optional() + .describe("Time when the invocation was last updated"), + workflow_id: z + .string() + .describe("ID of the workflow that was invoked"), + }) + .optional() + .describe( + "Specific invocation details (if invocation_id was provided)" + ), + invocations: z + .array( + z.object({ + create_time: z + .string() + .optional() + .describe("Time when the invocation was created"), + history_id: z + .string() + .describe("ID of the history where the invocation was run"), + id: z + .string() + .describe("The unique identifier of the invocation"), + state: z.string().describe("Current state of the invocation"), + update_time: z + .string() + .optional() + .describe("Time when the invocation was last updated"), + workflow_id: z + .string() + .describe("ID of the workflow that was invoked"), + }) + ) + .optional() + .describe("List of invocations (if invocation_id was not provided)"), + }) + .describe("Galaxy workflow invocation(s) information"), + }, + async (input: { + history_id?: string; + invocation_id?: string; + limit?: number; + step_details?: boolean; + view?: "element" | "collection"; + workflow_id?: string; + }): Promise<{ + invocation?: { + create_time?: string; + history_id: string; + id: string; + state: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + steps?: any[]; + update_time?: string; + workflow_id: string; + }; + invocations?: Array<{ + create_time?: string; + history_id: string; + id: string; + state: string; + update_time?: string; + workflow_id: string; + }>; + }> => { + try { + // Use the Galaxy MCP client to get workflow invocations + const response = (await galaxyMcpClient.call("get_invocations", { + history_id: input.history_id, + invocation_id: input.invocation_id, + limit: input.limit, + step_details: input.step_details || false, + view: input.view || "collection", + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + invocation?: { + create_time?: string; + history_id?: string; + id?: string; + state?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + steps?: any[]; + update_time?: string; + workflow_id?: string; + }; + invocations?: Array<{ + create_time?: string; + history_id?: string; + id?: string; + state?: string; + update_time?: string; + workflow_id?: string; + }>; + }; + + // Process the response to match our schema + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + const result: any = {}; + + if (response?.invocation) { + result.invocation = { + create_time: response.invocation.create_time + ? String(response.invocation.create_time) + : undefined, + history_id: String(response.invocation.history_id || ""), + id: String(response.invocation.id || ""), + state: String(response.invocation.state || ""), + steps: response.invocation.steps || undefined, + update_time: response.invocation.update_time + ? String(response.invocation.update_time) + : undefined, + workflow_id: String(response.invocation.workflow_id || ""), + }; + } + + if (response?.invocations) { + result.invocations = response.invocations.map((inv) => ({ + create_time: inv?.create_time ? String(inv.create_time) : undefined, + history_id: String(inv?.history_id || ""), + id: String(inv?.id || ""), + state: String(inv?.state || ""), + update_time: inv?.update_time ? String(inv.update_time) : undefined, + workflow_id: String(inv?.workflow_id || ""), + })); + } + + return result; + } catch (error) { + logger.error("Error getting Galaxy workflow invocations:", error); + throw new Error( + `Failed to get Galaxy workflow invocations: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get current Galaxy user information + */ +export const getGalaxyUserTool = ai.defineTool( + { + description: "Get information about the current Galaxy user", + inputSchema: z.object({}), + name: "getGalaxyUser", + outputSchema: z + .object({ + email: z.string().describe("User email address"), + id: z.string().describe("User ID"), + is_active: z + .boolean() + .optional() + .describe("Whether the user account is active"), + is_admin: z + .boolean() + .optional() + .describe("Whether the user is an admin"), + nice_total_disk_usage: z + .string() + .optional() + .describe("Human-readable disk usage"), + preferences: z.record(z.any()).optional().describe("User preferences"), + quota_percent: z + .number() + .optional() + .describe("Percentage of quota used"), + total_disk_usage: z + .number() + .optional() + .describe("Total disk usage in bytes"), + username: z.string().optional().describe("Username"), + }) + .describe("Galaxy user information"), + }, + async (): Promise<{ + email: string; + id: string; + is_active?: boolean; + is_admin?: boolean; + nice_total_disk_usage?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + preferences?: Record; + quota_percent?: number; + total_disk_usage?: number; + username?: string; + }> => { + try { + // Use the Galaxy MCP client to get current user information + const response = (await galaxyMcpClient.call( + "get_user", + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + {} as any + )) as unknown as { + email?: string; + id?: string; + is_active?: boolean; + is_admin?: boolean; + nice_total_disk_usage?: string; + preferences?: Record; + quota_percent?: number; + total_disk_usage?: number; + username?: string; + }; + + // Process the response to match our schema + const result = { + email: String(response?.email || ""), + id: String(response?.id || ""), + is_active: + typeof response?.is_active === "boolean" + ? response.is_active + : undefined, + is_admin: + typeof response?.is_admin === "boolean" + ? response.is_admin + : undefined, + nice_total_disk_usage: response?.nice_total_disk_usage + ? String(response.nice_total_disk_usage) + : undefined, + preferences: response?.preferences || undefined, + quota_percent: + typeof response?.quota_percent === "number" + ? response.quota_percent + : undefined, + total_disk_usage: + typeof response?.total_disk_usage === "number" + ? response.total_disk_usage + : undefined, + username: response?.username ? String(response.username) : undefined, + }; + + return result; + } catch (error) { + logger.error("Error getting Galaxy user information:", error); + throw new Error( + `Failed to get Galaxy user information: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get citation information for a Galaxy tool + */ +export const getGalaxyToolCitationsTool = ai.defineTool( + { + description: "Get citation information for a specific Galaxy tool", + inputSchema: z.object({ + tool_id: z.string().describe("ID of the tool to get citations for"), + }), + name: "getGalaxyToolCitations", + outputSchema: z + .object({ + citations: z + .array( + z.object({ + authors: z + .string() + .optional() + .describe("Authors of the citation"), + doi: z.string().optional().describe("Digital Object Identifier"), + title: z.string().optional().describe("Title of the citation"), + type: z.string().optional().describe("Type of citation"), + url: z.string().optional().describe("URL to the publication"), + year: z.string().optional().describe("Year of publication"), + }) + ) + .describe("List of citations for the tool"), + tool_name: z.string().describe("Name of the tool"), + tool_version: z.string().describe("Version of the tool"), + }) + .describe("Galaxy tool citation information"), + }, + async (input: { + tool_id: string; + }): Promise<{ + citations: Array<{ + authors?: string; + doi?: string; + title?: string; + type?: string; + url?: string; + year?: string; + }>; + tool_name: string; + tool_version: string; + }> => { + try { + // Use the Galaxy MCP client to get tool citations + const response = (await galaxyMcpClient.call("get_tool_citations", { + tool_id: input.tool_id, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as unknown as { + citations?: Array<{ + authors?: string; + doi?: string; + title?: string; + type?: string; + url?: string; + year?: string; + }>; + tool_name?: string; + tool_version?: string; + }; + + // Process the response to match our schema + const result = { + citations: Array.isArray(response?.citations) + ? response.citations.map((citation) => ({ + authors: citation?.authors ? String(citation.authors) : undefined, + doi: citation?.doi ? String(citation.doi) : undefined, + title: citation?.title ? String(citation.title) : undefined, + type: citation?.type ? String(citation.type) : undefined, + url: citation?.url ? String(citation.url) : undefined, + year: citation?.year ? String(citation.year) : undefined, + })) + : [], + tool_name: String(response?.tool_name || ""), + tool_version: String(response?.tool_version || ""), + }; + + return result; + } catch (error) { + logger.error("Error getting Galaxy tool citations:", error); + throw new Error( + `Failed to get Galaxy tool citations: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get a simplified list of history IDs and names + */ +export const listGalaxyHistoryIdsTool = ai.defineTool( + { + description: + "Get a simplified list of Galaxy history IDs and names for easy reference", + inputSchema: z.object({}), + name: "listGalaxyHistoryIds", + outputSchema: z + .array( + z.object({ + id: z.string().describe("History ID"), + name: z.string().describe("History name"), + }) + ) + .describe("List of Galaxy histories with IDs and names"), + }, + async (): Promise< + Array<{ + id: string; + name: string; + }> + > => { + try { + // Use the Galaxy MCP client to get simplified history list + const response = (await galaxyMcpClient.call( + "list_history_ids", + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + {} as any + )) as unknown as Array<{ id: string; name: string }>; + + // Process the response to match our schema + if (!Array.isArray(response)) { + return []; + } + + // Map the response to our schema + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + const result = response.map((history: any) => ({ + id: String(history?.id || ""), + name: String(history?.name || "Unnamed"), + })); + + return result; + } catch (error) { + logger.error("Error listing Galaxy history IDs:", error); + throw new Error( + `Failed to list Galaxy history IDs: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get detailed information about a specific Galaxy tool + */ +export const getGalaxyToolDetailsTool = ai.defineTool( + { + description: "Get detailed information about a specific Galaxy tool", + inputSchema: z.object({ + io_details: z + .boolean() + .optional() + .describe("Whether to include input/output details (default: false)"), + tool_id: z.string().describe("ID of the tool to get details for"), + }), + name: "getGalaxyToolDetails", + outputSchema: z + .object({ + description: z.string().optional().describe("Tool description"), + id: z.string().describe("Tool ID"), + inputs: z + .array( + z.object({ + help: z.string().optional().describe("Input help text"), + label: z.string().optional().describe("Input label"), + name: z.string().describe("Input name"), + optional: z + .boolean() + .optional() + .describe("Whether the input is optional"), + type: z.string().optional().describe("Input type"), + }) + ) + .optional() + .describe("Tool inputs (only if io_details is true)"), + name: z.string().describe("Tool name"), + outputs: z + .array( + z.object({ + format: z.string().optional().describe("Output format"), + label: z.string().optional().describe("Output label"), + name: z.string().describe("Output name"), + }) + ) + .optional() + .describe("Tool outputs (only if io_details is true)"), + panel_section_id: z + .string() + .optional() + .describe("Tool panel section ID"), + panel_section_name: z + .string() + .optional() + .describe("Tool panel section name"), + version: z.string().optional().describe("Tool version"), + }) + .describe("Galaxy tool details"), + }, + async (input: { + io_details?: boolean; + tool_id: string; + }): Promise<{ + description?: string; + id: string; + inputs?: Array<{ + help?: string; + label?: string; + name: string; + optional?: boolean; + type?: string; + }>; + name: string; + outputs?: Array<{ + format?: string; + label?: string; + name: string; + }>; + panel_section_id?: string; + panel_section_name?: string; + version?: string; + }> => { + try { + // Use the Galaxy MCP client to get tool details + const response = (await galaxyMcpClient.call("get_tool_details", { + io_details: input.io_details === true, + tool_id: input.tool_id, + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + } as any)) as any; + + // Process the response to match our schema + const result: { + description?: string; + id: string; + inputs?: Array<{ + help?: string; + label?: string; + name: string; + optional?: boolean; + type?: string; + }>; + name: string; + outputs?: Array<{ + format?: string; + label?: string; + name: string; + }>; + panel_section_id?: string; + panel_section_name?: string; + version?: string; + } = { + description: response?.description + ? String(response.description) + : undefined, + id: String(response?.id || ""), + name: String(response?.name || ""), + panel_section_id: response?.panel_section_id + ? String(response.panel_section_id) + : undefined, + panel_section_name: response?.panel_section_name + ? String(response.panel_section_name) + : undefined, + version: response?.version ? String(response.version) : undefined, + }; + + // Add inputs and outputs if io_details was requested + if (input.io_details === true) { + if (Array.isArray(response?.inputs)) { + result.inputs = response.inputs.map( + (inputItem: Record) => ({ + help: inputItem?.help ? String(inputItem.help) : undefined, + label: inputItem?.label ? String(inputItem.label) : undefined, + name: String(inputItem?.name || ""), + optional: + typeof inputItem?.optional === "boolean" + ? inputItem.optional + : undefined, + type: inputItem?.type ? String(inputItem.type) : undefined, + }) + ); + } + + if (Array.isArray(response?.outputs)) { + result.outputs = response.outputs.map( + (output: Record) => ({ + format: output?.format ? String(output.format) : undefined, + label: output?.label ? String(output.label) : undefined, + name: String(output?.name || ""), + }) + ); + } + } + + return result; + } catch (error) { + logger.error("Error getting Galaxy tool details:", error); + throw new Error( + `Failed to get Galaxy tool details: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get the tool panel structure from Galaxy + */ +export const getGalaxyToolPanelTool = ai.defineTool( + { + description: "Get the tool panel structure (toolbox) from Galaxy", + inputSchema: z.object({}), + name: "getGalaxyToolPanel", + outputSchema: z + .object({ + tool_panel: z + .array( + z.object({ + elems: z + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + .array(z.any()) + .optional() + .describe("Section elements (tools or subsections)"), + id: z.string().optional().describe("Section ID"), + model_class: z.string().optional().describe("Model class"), + name: z.string().optional().describe("Section name"), + }) + ) + .describe("Tool panel sections"), + }) + .describe("Galaxy tool panel structure"), + }, + async (): Promise<{ + tool_panel: Array<{ + elems?: Array; + id?: string; + model_class?: string; + name?: string; + }>; + }> => { + try { + // Use the Galaxy MCP client to get the tool panel + const response = (await galaxyMcpClient.call( + "get_tool_panel", + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + {} as any + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- what would marius do + )) as any; + + // Process the response to match our schema + const result = { + tool_panel: Array.isArray(response?.tool_panel) + ? response.tool_panel + : [], + }; + + return result; + } catch (error) { + logger.error("Error getting Galaxy tool panel:", error); + throw new Error( + `Failed to get Galaxy tool panel: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +// Export all Galaxy tools as an array +export const galaxyTools = [ + getGalaxyServerInfoTool, + getGalaxyHistoriesTool, + getHistoryDetailsTool, + searchGalaxyToolsTool, + createGalaxyHistoryTool, + runGalaxyToolTool, + getIwcWorkflowsTool, + searchIwcWorkflowsTool, + importWorkflowFromIwcTool, + getGalaxyJobDetailsTool, + uploadFileToGalaxyTool, + filterToolsByDatasetTool, + getGalaxyInvocationsTool, + getGalaxyUserTool, + getGalaxyToolCitationsTool, + listGalaxyHistoryIdsTool, + getGalaxyToolDetailsTool, + getGalaxyToolPanelTool, + // Additional tools can be added here +]; diff --git a/genkit/src/index.ts b/genkit/src/index.ts new file mode 100644 index 00000000..92ebf892 --- /dev/null +++ b/genkit/src/index.ts @@ -0,0 +1,647 @@ +import { z } from "genkit"; +import { logger } from "@genkit-ai/core/logging"; +import { dataStore } from "./dataStore"; +import { ai } from "./ai"; +import { ncbiTools } from "./ncbiTools"; +import { galaxyTools } from "./galaxyTools"; +import { FileSessionStore } from "./sessionStore"; + +// Initialize session store for chat message history +const sessionStore = new FileSessionStore("./data/sessions"); + +// Define schemas for common inputs +const SessionIdSchema = z.string().describe("Session ID for chat history"); + +// Tool: Get BRC Organisms +export const getOrganisms = ai.defineTool( + { + description: "Get a list of all organisms in the BRC Analytics catalog", + inputSchema: z.object({ + limit: z + .number() + .optional() + .describe("Optional limit on the number of organisms to return"), + offset: z.number().optional().describe("Optional offset for pagination"), + }), + name: "brc_get_organisms", + outputSchema: z.object({ + organisms: z.array( + z.object({ + assemblyCount: z.number(), + commonName: z.string().nullable(), + taxonomicGroup: z.array(z.string()), + taxonomicLevelClass: z.string(), + taxonomicLevelDomain: z.string(), + taxonomicLevelFamily: z.string(), + taxonomicLevelGenus: z.string(), + taxonomicLevelOrder: z.string(), + taxonomicLevelPhylum: z.string(), + taxonomicLevelSpecies: z.string(), + taxonomicLevelStrain: z.string().nullable(), + taxonomyId: z.string(), + }) + ), + total: z.number(), + }), + }, + async (input: { limit?: number; offset?: number }) => { + try { + const organisms = await dataStore.getOrganisms(); + const limit = input.limit || organisms.length; + const offset = input.offset || 0; + + const paginatedOrganisms = organisms + .slice(offset, offset + limit) + .map((org) => { + // Get the first genome for each organism to extract taxonomy info + const genome = org.genomes[0]; + return { + assemblyCount: org.assemblyCount, + commonName: genome.commonName, + taxonomicGroup: genome.taxonomicGroup, + taxonomicLevelClass: genome.taxonomicLevelClass, + taxonomicLevelDomain: genome.taxonomicLevelDomain, + taxonomicLevelFamily: genome.taxonomicLevelFamily, + taxonomicLevelGenus: genome.taxonomicLevelGenus, + taxonomicLevelOrder: genome.taxonomicLevelOrder, + taxonomicLevelPhylum: genome.taxonomicLevelPhylum, + taxonomicLevelSpecies: genome.taxonomicLevelSpecies, + taxonomicLevelStrain: genome.taxonomicLevelStrain || null, + taxonomyId: genome.ncbiTaxonomyId, + }; + }); + + return { + organisms: paginatedOrganisms, + total: organisms.length, + }; + } catch (error) { + logger.error("Error in getOrganisms:", error); + throw error; + } + } +); + +// Tool: Get BRC Organism Details +export const getOrganismDetails = ai.defineTool( + { + description: + "Get detailed information about a specific organism by taxonomy ID from the BRC Analytics catalog", + inputSchema: z.object({ + taxonomy_id: z.string().describe("NCBI Taxonomy ID of the organism"), + }), + name: "brc_get_organism_details", + outputSchema: z.object({ + error: z.string().optional(), + organism: z + .object({ + assemblyCount: z.number(), + commonName: z.string().nullable(), + genomes: z.array( + z.object({ + accession: z.string(), + gcPercent: z.number().nullable(), + isRef: z.string(), + length: z.number(), + strainName: z.string().nullable(), + }) + ), + taxonomicGroup: z.array(z.string()), + taxonomyId: z.string(), + }) + .nullable(), + }), + }, + async (input: { taxonomy_id: string }) => { + try { + const organism = await dataStore.getOrganismByTaxonomyId( + input.taxonomy_id + ); + + if (!organism) { + return { + error: `Organism with taxonomy ID ${input.taxonomy_id} not found`, + organism: null, + }; + } + + // Get the first genome for each organism to extract taxonomy info + const genome = organism.genomes[0]; + + return { + organism: { + assemblyCount: organism.assemblyCount, + commonName: genome.commonName, + genomes: organism.genomes.map((g) => ({ + accession: g.accession, + gcPercent: g.gcPercent, + isRef: g.isRef, + length: g.length, + strainName: g.strainName, + })), + taxonomicGroup: genome.taxonomicGroup, + taxonomyId: genome.ncbiTaxonomyId, + }, + }; + } catch (error) { + logger.error("Error in getOrganismDetails:", error); + return { + error: `Error retrieving organism: ${error instanceof Error ? error.message : String(error)}`, + organism: null, + }; + } + } +); + +// Tool: Get BRC Assemblies +export const getAssemblies = ai.defineTool( + { + description: "Get a list of all assemblies in the BRC Analytics catalog", + inputSchema: z.object({ + limit: z + .number() + .optional() + .describe("Optional limit on the number of assemblies to return"), + offset: z.number().optional().describe("Optional offset for pagination"), + taxonomy_id: z + .string() + .optional() + .describe("Optional taxonomy ID to filter assemblies"), + }), + name: "brc_get_assemblies", + outputSchema: z.object({ + assemblies: z.array( + z.object({ + accession: z.string(), + gcPercent: z.number().nullable(), + isRef: z.string(), + length: z.number(), + strainName: z.string().nullable(), + taxonomyId: z.string(), + }) + ), + total: z.number(), + }), + }, + async (input: { limit?: number; offset?: number; taxonomy_id?: string }) => { + try { + let assemblies; + + if (input.taxonomy_id) { + assemblies = await dataStore.getAssembliesByTaxonomyId( + input.taxonomy_id + ); + } else { + assemblies = await dataStore.getAssemblies(); + } + + const limit = input.limit || assemblies.length; + const offset = input.offset || 0; + + const paginatedAssemblies = assemblies + .slice(offset, offset + limit) + .map((assembly) => ({ + accession: assembly.accession, + gcPercent: assembly.gcPercent, + isRef: assembly.isRef, + length: assembly.length, + strainName: assembly.strainName, + taxonomyId: assembly.ncbiTaxonomyId, + })); + + return { + assemblies: paginatedAssemblies, + total: assemblies.length, + }; + } catch (error) { + logger.error("Error in getAssemblies:", error); + throw error; + } + } +); + +// Tool: Get BRC Assembly Details +export const getAssemblyDetails = ai.defineTool( + { + description: + "Get detailed information about a specific assembly by accession from the BRC Analytics catalog", + inputSchema: z.object({ + accession: z.string().describe("Accession ID of the assembly"), + }), + name: "brc_get_assembly_details", + outputSchema: z.object({ + assembly: z + .object({ + accession: z.string(), + coverage: z.string(), + gcPercent: z.number().nullable(), + geneModelUrl: z.string().nullable(), + isRef: z.string(), + length: z.number(), + level: z.string(), + scaffoldCount: z.number(), + scaffoldL50: z.number(), + scaffoldN50: z.number(), + strainName: z.string().nullable(), + taxonomyId: z.string(), + }) + .nullable(), + error: z.string().optional(), + }), + }, + async (input: { accession: string }) => { + try { + const assembly = await dataStore.getAssemblyByAccession(input.accession); + + if (!assembly) { + return { + assembly: null, + error: `Assembly with accession ${input.accession} not found`, + }; + } + + return { + assembly: { + accession: assembly.accession, + coverage: assembly.coverage, + gcPercent: assembly.gcPercent, + geneModelUrl: assembly.geneModelUrl, + isRef: assembly.isRef, + length: assembly.length, + level: assembly.level, + scaffoldCount: assembly.scaffoldCount, + scaffoldL50: assembly.scaffoldL50, + scaffoldN50: assembly.scaffoldN50, + strainName: assembly.strainName, + taxonomyId: assembly.ncbiTaxonomyId, + }, + }; + } catch (error) { + logger.error("Error in getAssemblyDetails:", error); + return { + assembly: null, + error: `Error retrieving assembly: ${error instanceof Error ? error.message : String(error)}`, + }; + } + } +); + +// Tool: Get BRC Workflows +export const getWorkflows = ai.defineTool( + { + description: "Get a list of all workflows in the BRC Analytics catalog", + inputSchema: z.object({ + limit: z + .number() + .optional() + .describe("Optional limit on the number of workflows to return"), + offset: z.number().optional().describe("Optional offset for pagination"), + tag: z.string().optional().describe("Optional tag to filter workflows"), + }), + name: "brc_get_workflows", + outputSchema: z.object({ + total: z.number(), + workflows: z.array( + z.object({ + description: z.string(), + id: z.string(), + name: z.string(), + tags: z.array(z.string()), + version: z.string(), + }) + ), + }), + }, + async (input: { limit?: number; offset?: number; tag?: string }) => { + try { + let workflows; + + if (input.tag) { + workflows = await dataStore.getWorkflowsByTag(input.tag); + } else { + workflows = await dataStore.getWorkflows(); + } + + const limit = input.limit || workflows.length; + const offset = input.offset || 0; + + const paginatedWorkflows = workflows + .slice(offset, offset + limit) + .map((workflow, index) => ({ + description: workflow.description || "", + id: workflow.id || `workflow-${index + 1}`, + name: workflow.name || "Unnamed Workflow", + tags: Array.isArray(workflow.tags) ? workflow.tags : [], + version: workflow.version || "1.0.0", + })); + + return { + total: workflows.length, + workflows: paginatedWorkflows, + }; + } catch (error) { + logger.error("Error in getWorkflows:", error); + throw error; + } + } +); + +// Tool: Get BRC Workflow Details +export const getWorkflowDetails = ai.defineTool( + { + description: + "Get detailed information about a specific workflow by ID from the BRC Analytics catalog", + inputSchema: z.object({ + workflow_id: z.string().describe("ID of the workflow"), + }), + name: "brc_get_workflow_details", + outputSchema: z.object({ + error: z.string().optional(), + workflow: z + .object({ + description: z.string(), + id: z.string(), + name: z.string(), + parameters: z.array( + z.object({ + description: z.string().optional(), + id: z.string(), + name: z.string(), + required: z.boolean(), + type: z.string(), + }) + ), + steps: z.array( + z.object({ + description: z.string().optional(), + id: z.string(), + name: z.string(), + tool_id: z.string(), + }) + ), + tags: z.array(z.string()), + version: z.string(), + }) + .nullable(), + }), + }, + async (input: { workflow_id: string }) => { + try { + const workflow = await dataStore.getWorkflowById(input.workflow_id); + + if (!workflow) { + return { + error: `Workflow with ID ${input.workflow_id} not found`, + workflow: null, + }; + } + + return { + workflow: { + description: workflow.description, + id: workflow.id, + name: workflow.name, + parameters: workflow.parameters.map((param) => ({ + description: param.description, + id: param.id, + name: param.name, + required: param.required, + type: param.type, + })), + steps: workflow.steps.map((step) => ({ + description: step.description, + id: step.id, + name: step.name, + tool_id: step.tool_id, + })), + tags: workflow.tags, + version: workflow.version, + }, + }; + } catch (error) { + logger.error("Error in getWorkflowDetails:", error); + return { + error: `Error retrieving workflow: ${error instanceof Error ? error.message : String(error)}`, + workflow: null, + }; + } + } +); + +// Tool: Get BRC Outbreaks +export const getOutbreaks = ai.defineTool( + { + description: "Get a list of all outbreaks in the BRC Analytics catalog", + inputSchema: z.object({ + limit: z + .number() + .optional() + .describe("Optional limit on the number of outbreaks to return"), + offset: z.number().optional().describe("Optional offset for pagination"), + }), + name: "brc_get_outbreaks", + outputSchema: z.object({ + outbreaks: z.array( + z.object({ + description: z.string(), + id: z.string(), + name: z.string(), + priority: z.string(), + taxonomyId: z.string(), + }) + ), + total: z.number(), + }), + }, + async (input: { limit?: number; offset?: number }) => { + try { + const outbreaks = await dataStore.getOutbreaks(); + const limit = input.limit || outbreaks.length; + const offset = input.offset || 0; + + const paginatedOutbreaks = outbreaks + .slice(offset, offset + limit) + .map((outbreak) => ({ + description: outbreak.description, + id: outbreak.id, + name: outbreak.name, + priority: outbreak.priority, + taxonomyId: outbreak.taxonomyId, + })); + + return { + outbreaks: paginatedOutbreaks, + total: outbreaks.length, + }; + } catch (error) { + logger.error("Error in getOutbreaks:", error); + throw error; + } + } +); + +// Tool: Get BRC Outbreak Details +export const getOutbreakDetails = ai.defineTool( + { + description: + "Get detailed information about a specific outbreak by ID from the BRC Analytics catalog", + inputSchema: z.object({ + outbreak_id: z.string().describe("ID of the outbreak"), + }), + name: "brc_get_outbreak_details", + outputSchema: z.object({ + error: z.string().optional(), + outbreak: z + .object({ + description: z.string(), + id: z.string(), + name: z.string(), + priority: z.string(), + resources: z.array( + z.object({ + title: z.string(), + type: z.string(), + url: z.string(), + }) + ), + taxonomyId: z.string(), + }) + .nullable(), + }), + }, + async (input: { outbreak_id: string }) => { + try { + const outbreak = await dataStore.getOutbreakById(input.outbreak_id); + + if (!outbreak) { + return { + error: `Outbreak with ID ${input.outbreak_id} not found`, + outbreak: null, + }; + } + + return { + outbreak: { + description: outbreak.description, + id: outbreak.id, + name: outbreak.name, + priority: outbreak.priority, + resources: outbreak.resources, + taxonomyId: outbreak.taxonomyId, + }, + }; + } catch (error) { + logger.error("Error in getOutbreakDetails:", error); + return { + error: `Error retrieving outbreak: ${error instanceof Error ? error.message : String(error)}`, + outbreak: null, + }; + } + } +); + +// Group all BRC Analytics tools +const brcTools = [ + getOrganisms, + getOrganismDetails, + getAssemblies, + getAssemblyDetails, + getWorkflows, + getWorkflowDetails, + getOutbreaks, + getOutbreakDetails, +]; + +// Combine all tools into a single array for the chat flow +const allTools = [ + ...brcTools, + ...galaxyTools, // Galaxy tools imported from galaxyTools.ts + ...ncbiTools, // NCBI Datasets API tools +]; + +// Main chat flow +export const chatFlow = ai.defineFlow( + { + inputSchema: z.object({ + message: z.string().describe("User message"), + session_id: SessionIdSchema.optional().describe( + "Optional session ID for chat history" + ), + }), + name: "chatFlow", + outputSchema: z.string().describe("Assistant response"), + }, + async (input: { message: string; session_id?: string }) => { + // Generate or use the provided session ID + const sessionId = input.session_id || `session_${Date.now()}`; + + // Get or create the session + let session = await sessionStore.get(sessionId); + if (!session) { + session = await sessionStore.create(sessionId); + } + + // Add the user message to the conversation history + session.messages.push({ content: input.message, role: "user" }); + + // Save the updated session + await sessionStore.save(sessionId, session); + + // Prepare the prompt with conversation history + const conversationHistory = session.messages + .map( + (msg) => `${msg.role === "user" ? "User" : "Assistant"}: ${msg.content}` + ) + .join("\n\n"); + + const prompt = `You are BioBuddy, a BRC Analytics assistant and helpful AI that can provide information about organisms, assemblies, workflows, and outbreaks in the BRC Analytics catalog. You can also interact with the Galaxy bioinformatics platform and NCBI Datasets API to perform various tasks, including: + +# BRC Analytics Catalog +- Get information about organisms in the BRC catalog +- Search for specific organisms by taxonomy ID +- Get details about genome assemblies +- Find workflows related to specific organisms or analyses +- Access outbreak information and related data + +# Galaxy Platform +- Get Galaxy server information +- Search and retrieve workflows from the Interoperable Workflow Catalog (IWC) +- Import workflows from IWC into Galaxy +- List and manage Galaxy histories +- Create new Galaxy histories +- Search for Galaxy tools by name +- Run Galaxy tools with appropriate parameters +- Upload files to Galaxy for analysis + +# NCBI Datasets API +- Search for genomic data across NCBI databases +- Retrieve genome assemblies and annotations +- Access taxonomic information +- Download sequence data for specific organisms + +Conversation history: +${conversationHistory} + +Based on this conversation, please provide a helpful response to the user's latest message. Use the available tools to retrieve information from the BRC Analytics catalog or interact with Galaxy as needed.`; + + // Generate response with tools + const llmResponse = await ai.generate({ + prompt, + tools: allTools, + }); + + const responseText = llmResponse.text; + + // Add the assistant response to the conversation history + session.messages.push({ content: responseText, role: "assistant" }); + + // Save the updated session + await sessionStore.save(sessionId, session); + + // Return the response text + return responseText; + } +); + +// Export the chat flow +export default chatFlow; diff --git a/genkit/src/ncbiClient.ts b/genkit/src/ncbiClient.ts new file mode 100644 index 00000000..91959300 --- /dev/null +++ b/genkit/src/ncbiClient.ts @@ -0,0 +1,249 @@ +import axios from "axios"; +import { logger } from "@genkit-ai/core/logging"; + +// Base URL for NCBI Datasets API v2 +const NCBI_API_BASE_URL = "https://api.ncbi.nlm.nih.gov/datasets/v2"; + +/** + * Client for interacting with the NCBI Datasets API + */ +export class NcbiDatasetsClient { + private apiKey?: string; + private baseUrl: string; + + /** + * Create a new NCBI Datasets API client + * @param apiKey - Optional API key for higher rate limits + * @param baseUrl - Optional custom base URL + */ + constructor(apiKey?: string, baseUrl: string = NCBI_API_BASE_URL) { + this.apiKey = apiKey; + this.baseUrl = baseUrl; + } + + /** + * Make a request to the NCBI Datasets API + * @param endpoint - API endpoint path + * @param params - Optional query parameters + * @returns Response data + */ + async request( + endpoint: string, + params: Record = {} + ): Promise { + try { + const url = `${this.baseUrl}${endpoint}`; + + const headers: Record = { + Accept: "application/json", + }; + + // Add API key if available + if (this.apiKey) { + headers["api-key"] = this.apiKey; + } + + logger.debug(`Making request to NCBI API: ${url}`); + + const response = await axios.get(url, { + headers, + params, + }); + + return response.data as T; + } catch (error) { + if (axios.isAxiosError(error)) { + const statusCode = error.response?.status; + const errorMessage = error.response?.data?.message || error.message; + + logger.error(`NCBI API error (${statusCode}): ${errorMessage}`); + throw new Error(`NCBI API error (${statusCode}): ${errorMessage}`); + } + + logger.error("Error making NCBI API request:", error); + throw new Error( + `Error making NCBI API request: ${error instanceof Error ? error.message : String(error)}` + ); + } + } + + /** + * Get genome annotation report by accession + * @param accession - Genome assembly accession + * @returns Annotation report data + */ + async getGenomeAnnotationReport(accession: string): Promise { + return this.request(`/genome/accession/${accession}/annotation_report`); + } + + /** + * Get genome dataset report by accessions + * @param accessions - Array of genome assembly accessions + * @returns Dataset report data + */ + async getGenomeDatasetReport(accessions: string[]): Promise { + return this.request( + `/genome/accession/${accessions.join(",")}/dataset_report` + ); + } + + /** + * Get genome sequence reports by accession + * @param accession - Genome assembly accession + * @returns Sequence reports data + */ + async getGenomeSequenceReports(accession: string): Promise { + return this.request(`/genome/accession/${accession}/sequence_reports`); + } + + /** + * Get genome dataset report by assembly names + * @param assemblyNames - Array of assembly names + * @returns Dataset report data + */ + async getGenomeByAssemblyNameDatasetReport( + assemblyNames: string[] + ): Promise { + return this.request( + `/genome/assembly_name/${assemblyNames.join(",")}/dataset_report` + ); + } + + /** + * Get genome dataset report by BioProject IDs + * @param bioprojects - Array of BioProject IDs + * @returns Dataset report data + */ + async getGenomeByBioprojectDatasetReport( + bioprojects: string[] + ): Promise { + return this.request( + `/genome/bioproject/${bioprojects.join(",")}/dataset_report` + ); + } + + /** + * Get genome dataset report by BioSample IDs + * @param biosampleIds - Array of BioSample IDs + * @returns Dataset report data + */ + async getGenomeByBiosampleDatasetReport( + biosampleIds: string[] + ): Promise { + return this.request( + `/genome/biosample/${biosampleIds.join(",")}/dataset_report` + ); + } + + /** + * Get genome dataset report by taxonomy IDs + * @param taxons - Array of taxonomy IDs + * @returns Dataset report data + */ + async getGenomeByTaxonDatasetReport(taxons: string[]): Promise { + return this.request(`/genome/taxon/${taxons.join(",")}/dataset_report`); + } + + /** + * Get gene data by accessions + * @param accessions - Array of gene accessions + * @returns Gene data + */ + async getGeneByAccession(accessions: string[]): Promise { + return this.request(`/gene/accession/${accessions.join(",")}`); + } + + /** + * Get gene orthologs by gene ID + * @param geneId - Gene ID + * @returns Ortholog data + */ + async getGeneOrthologs(geneId: string): Promise { + return this.request(`/gene/id/${geneId}/orthologs`); + } + + /** + * Get gene data by gene IDs + * @param geneIds - Array of gene IDs + * @returns Gene data + */ + async getGeneById(geneIds: string[]): Promise { + return this.request(`/gene/id/${geneIds.join(",")}`); + } + + /** + * Get gene links by gene IDs + * @param geneIds - Array of gene IDs + * @returns Gene links data + */ + async getGeneLinks(geneIds: string[]): Promise { + return this.request(`/gene/id/${geneIds.join(",")}/links`); + } + + /** + * Get gene data by taxonomy ID + * @param taxon - Taxonomy ID + * @returns Gene data + */ + async getGeneByTaxon(taxon: string): Promise { + return this.request(`/gene/taxon/${taxon}`); + } + + /** + * Get gene chromosome summary by taxonomy ID and annotation name + * @param taxon - Taxonomy ID + * @param annotationName - Annotation name + * @returns Chromosome summary data + */ + async getGeneChromosomeSummary( + taxon: string, + annotationName: string + ): Promise { + return this.request( + `/gene/taxon/${taxon}/annotation/${annotationName}/chromosome_summary` + ); + } + + /** + * Get taxonomy dataset report by taxonomy IDs + * @param taxons - Array of taxonomy IDs + * @returns Dataset report data + */ + async getTaxonomyDatasetReport(taxons: string[]): Promise { + return this.request(`/taxonomy/taxon/${taxons.join(",")}/dataset_report`); + } + + /** + * Get taxonomy name report by taxonomy IDs + * @param taxons - Array of taxonomy IDs + * @returns Name report data + */ + async getTaxonomyNameReport(taxons: string[]): Promise { + return this.request(`/taxonomy/taxon/${taxons.join(",")}/name_report`); + } + + /** + * Get BioSample report by accessions + * @param accessions - Array of BioSample accessions + * @returns BioSample report data + */ + async getBiosampleReport(accessions: string[]): Promise { + return this.request( + `/biosample/accession/${accessions.join(",")}/biosample_report` + ); + } + + /** + * Get organelle dataset report by accessions + * @param accessions - Array of organelle accessions + * @returns Dataset report data + */ + async getOrganelleDatasetReport(accessions: string[]): Promise { + return this.request( + `/organelle/accessions/${accessions.join(",")}/dataset_report` + ); + } +} + +// Create and export a singleton instance +export const ncbiClient = new NcbiDatasetsClient(process.env.NCBI_API_KEY); diff --git a/genkit/src/ncbiTools.ts b/genkit/src/ncbiTools.ts new file mode 100644 index 00000000..bb7215e1 --- /dev/null +++ b/genkit/src/ncbiTools.ts @@ -0,0 +1,558 @@ +import { z } from "genkit"; +import { logger } from "@genkit-ai/core/logging"; +import { ncbiClient } from "./ncbiClient"; +import { ai } from "./ai"; + +/** + * Tool to get genome annotation report by accession + */ +export const getGenomeAnnotationReportTool = ai.defineTool( + { + description: + "Get genome annotation report for a specific genome assembly accession", + inputSchema: z.object({ + accession: z + .string() + .describe("Genome assembly accession (e.g., GCF_000001405.40)"), + }), + name: "getGenomeAnnotationReport", + outputSchema: z.any().describe("Genome annotation report data"), + }, + async (input: { accession: string }) => { + try { + logger.info( + `Getting genome annotation report for accession: ${input.accession}` + ); + const result = await ncbiClient.getGenomeAnnotationReport( + input.accession + ); + return result; + } catch (error) { + logger.error(`Error getting genome annotation report: ${error}`); + throw new Error( + `Failed to get genome annotation report: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get genome dataset report by accessions + */ +export const getGenomeDatasetReportTool = ai.defineTool( + { + description: + "Get genome dataset report for specific genome assembly accessions", + inputSchema: z.object({ + accessions: z + .array(z.string()) + .describe( + 'Array of genome assembly accessions (e.g., ["GCF_000001405.40", "GCF_000001635.27"])' + ), + }), + name: "getGenomeDatasetReport", + outputSchema: z.any().describe("Genome dataset report data"), + }, + async (input: { accessions: string[] }) => { + try { + logger.info( + `Getting genome dataset report for accessions: ${input.accessions.join(", ")}` + ); + const result = await ncbiClient.getGenomeDatasetReport(input.accessions); + return result; + } catch (error) { + logger.error(`Error getting genome dataset report: ${error}`); + throw new Error( + `Failed to get genome dataset report: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get genome sequence reports by accession + */ +export const getGenomeSequenceReportsTool = ai.defineTool( + { + description: + "Get genome sequence reports for a specific genome assembly accession", + inputSchema: z.object({ + accession: z + .string() + .describe("Genome assembly accession (e.g., GCF_000001405.40)"), + }), + name: "getGenomeSequenceReports", + outputSchema: z.any().describe("Genome sequence reports data"), + }, + async (input: { accession: string }) => { + try { + logger.info( + `Getting genome sequence reports for accession: ${input.accession}` + ); + const result = await ncbiClient.getGenomeSequenceReports(input.accession); + return result; + } catch (error) { + logger.error(`Error getting genome sequence reports: ${error}`); + throw new Error( + `Failed to get genome sequence reports: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get genome dataset report by assembly names + */ +export const getGenomeByAssemblyNameDatasetReportTool = ai.defineTool( + { + description: "Get genome dataset report for specific assembly names", + inputSchema: z.object({ + assemblyNames: z + .array(z.string()) + .describe('Array of assembly names (e.g., ["GRCh38.p14", "GRCm39"])'), + }), + name: "getGenomeByAssemblyNameDatasetReport", + outputSchema: z.any().describe("Genome dataset report data"), + }, + async (input: { assemblyNames: string[] }) => { + try { + logger.info( + `Getting genome dataset report for assembly names: ${input.assemblyNames.join(", ")}` + ); + const result = await ncbiClient.getGenomeByAssemblyNameDatasetReport( + input.assemblyNames + ); + return result; + } catch (error) { + logger.error( + `Error getting genome dataset report by assembly names: ${error}` + ); + throw new Error( + `Failed to get genome dataset report by assembly names: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get genome dataset report by BioProject IDs + */ +export const getGenomeByBioprojectDatasetReportTool = ai.defineTool( + { + description: "Get genome dataset report for specific BioProject IDs", + inputSchema: z.object({ + bioprojects: z + .array(z.string()) + .describe('Array of BioProject IDs (e.g., ["PRJNA164", "PRJNA31257"])'), + }), + name: "getGenomeByBioprojectDatasetReport", + outputSchema: z.any().describe("Genome dataset report data"), + }, + async (input: { bioprojects: string[] }) => { + try { + logger.info( + `Getting genome dataset report for bioprojects: ${input.bioprojects.join(", ")}` + ); + const result = await ncbiClient.getGenomeByBioprojectDatasetReport( + input.bioprojects + ); + return result; + } catch (error) { + logger.error( + `Error getting genome dataset report by bioprojects: ${error}` + ); + throw new Error( + `Failed to get genome dataset report by bioprojects: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get genome dataset report by BioSample IDs + */ +export const getGenomeByBiosampleDatasetReportTool = ai.defineTool( + { + description: "Get genome dataset report for specific BioSample IDs", + inputSchema: z.object({ + biosampleIds: z + .array(z.string()) + .describe( + 'Array of BioSample IDs (e.g., ["SAMN02981385", "SAMN00000001"])' + ), + }), + name: "getGenomeByBiosampleDatasetReport", + outputSchema: z.any().describe("Genome dataset report data"), + }, + async (input: { biosampleIds: string[] }) => { + try { + logger.info( + `Getting genome dataset report for biosamples: ${input.biosampleIds.join(", ")}` + ); + const result = await ncbiClient.getGenomeByBiosampleDatasetReport( + input.biosampleIds + ); + return result; + } catch (error) { + logger.error( + `Error getting genome dataset report by biosamples: ${error}` + ); + throw new Error( + `Failed to get genome dataset report by biosamples: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get genome dataset report by taxonomy IDs + */ +export const getGenomeByTaxonDatasetReportTool = ai.defineTool( + { + description: "Get genome dataset report for specific taxonomy IDs", + inputSchema: z.object({ + taxons: z + .array(z.string()) + .describe('Array of taxonomy IDs (e.g., ["9606", "10090"])'), + }), + name: "getGenomeByTaxonDatasetReport", + outputSchema: z.any().describe("Genome dataset report data"), + }, + async (input: { taxons: string[] }) => { + try { + logger.info( + `Getting genome dataset report for taxons: ${input.taxons.join(", ")}` + ); + const result = await ncbiClient.getGenomeByTaxonDatasetReport( + input.taxons + ); + return result; + } catch (error) { + logger.error(`Error getting genome dataset report by taxons: ${error}`); + throw new Error( + `Failed to get genome dataset report by taxons: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get gene data by accessions + */ +export const getGeneByAccessionTool = ai.defineTool( + { + description: "Get gene data for specific gene accessions", + inputSchema: z.object({ + accessions: z + .array(z.string()) + .describe( + 'Array of gene accessions (e.g., ["NM_000014.6", "NM_000015.4"])' + ), + }), + name: "getGeneByAccession", + outputSchema: z.any().describe("Gene data"), + }, + async (input: { accessions: string[] }) => { + try { + logger.info( + `Getting gene data for accessions: ${input.accessions.join(", ")}` + ); + const result = await ncbiClient.getGeneByAccession(input.accessions); + return result; + } catch (error) { + logger.error(`Error getting gene data by accessions: ${error}`); + throw new Error( + `Failed to get gene data by accessions: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get gene orthologs by gene ID + */ +export const getGeneOrthologsTool = ai.defineTool( + { + description: "Get gene orthologs for a specific gene ID", + inputSchema: z.object({ + geneId: z.string().describe('Gene ID (e.g., "5111")'), + }), + name: "getGeneOrthologs", + outputSchema: z.any().describe("Gene ortholog data"), + }, + async (input: { geneId: string }) => { + try { + logger.info(`Getting gene orthologs for gene ID: ${input.geneId}`); + const result = await ncbiClient.getGeneOrthologs(input.geneId); + return result; + } catch (error) { + logger.error(`Error getting gene orthologs: ${error}`); + throw new Error( + `Failed to get gene orthologs: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get gene data by gene IDs + */ +export const getGeneByIdTool = ai.defineTool( + { + description: "Get gene data for specific gene IDs", + inputSchema: z.object({ + geneIds: z + .array(z.string()) + .describe('Array of gene IDs (e.g., ["5111", "672"])'), + }), + name: "getGeneById", + outputSchema: z.any().describe("Gene data"), + }, + async (input: { geneIds: string[] }) => { + try { + logger.info( + `Getting gene data for gene IDs: ${input.geneIds.join(", ")}` + ); + const result = await ncbiClient.getGeneById(input.geneIds); + return result; + } catch (error) { + logger.error(`Error getting gene data by IDs: ${error}`); + throw new Error( + `Failed to get gene data by IDs: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get gene links by gene IDs + */ +export const getGeneLinksTool = ai.defineTool( + { + description: "Get gene links for specific gene IDs", + inputSchema: z.object({ + geneIds: z + .array(z.string()) + .describe('Array of gene IDs (e.g., ["5111", "672"])'), + }), + name: "getGeneLinks", + outputSchema: z.any().describe("Gene links data"), + }, + async (input: { geneIds: string[] }) => { + try { + logger.info( + `Getting gene links for gene IDs: ${input.geneIds.join(", ")}` + ); + const result = await ncbiClient.getGeneLinks(input.geneIds); + return result; + } catch (error) { + logger.error(`Error getting gene links: ${error}`); + throw new Error( + `Failed to get gene links: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get gene data by taxonomy ID + */ +export const getGeneByTaxonTool = ai.defineTool( + { + description: "Get gene data for a specific taxonomy ID", + inputSchema: z.object({ + taxon: z.string().describe('Taxonomy ID (e.g., "9606")'), + }), + name: "getGeneByTaxon", + outputSchema: z.any().describe("Gene data"), + }, + async (input: { taxon: string }) => { + try { + logger.info(`Getting gene data for taxon: ${input.taxon}`); + const result = await ncbiClient.getGeneByTaxon(input.taxon); + return result; + } catch (error) { + logger.error(`Error getting gene data by taxon: ${error}`); + throw new Error( + `Failed to get gene data by taxon: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get gene chromosome summary by taxonomy ID and annotation name + */ +export const getGeneChromosomeSummaryTool = ai.defineTool( + { + description: + "Get gene chromosome summary for a specific taxonomy ID and annotation name", + inputSchema: z.object({ + annotationName: z.string().describe('Annotation name (e.g., "RefSeq")'), + taxon: z.string().describe('Taxonomy ID (e.g., "9606")'), + }), + name: "getGeneChromosomeSummary", + outputSchema: z.any().describe("Chromosome summary data"), + }, + async (input: { annotationName: string; taxon: string }) => { + try { + logger.info( + `Getting gene chromosome summary for taxon: ${input.taxon}, annotation: ${input.annotationName}` + ); + const result = await ncbiClient.getGeneChromosomeSummary( + input.taxon, + input.annotationName + ); + return result; + } catch (error) { + logger.error(`Error getting gene chromosome summary: ${error}`); + throw new Error( + `Failed to get gene chromosome summary: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get taxonomy dataset report by taxonomy IDs + */ +export const getTaxonomyDatasetReportTool = ai.defineTool( + { + description: "Get taxonomy dataset report for specific taxonomy IDs", + inputSchema: z.object({ + taxons: z + .array(z.string()) + .describe('Array of taxonomy IDs (e.g., ["9606", "10090"])'), + }), + name: "getTaxonomyDatasetReport", + outputSchema: z.any().describe("Taxonomy dataset report data"), + }, + async (input: { taxons: string[] }) => { + try { + logger.info( + `Getting taxonomy dataset report for taxons: ${input.taxons.join(", ")}` + ); + const result = await ncbiClient.getTaxonomyDatasetReport(input.taxons); + return result; + } catch (error) { + logger.error(`Error getting taxonomy dataset report: ${error}`); + throw new Error( + `Failed to get taxonomy dataset report: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get taxonomy name report by taxonomy IDs + */ +export const getTaxonomyNameReportTool = ai.defineTool( + { + description: "Get taxonomy name report for specific taxonomy IDs", + inputSchema: z.object({ + taxons: z + .array(z.string()) + .describe('Array of taxonomy IDs (e.g., ["9606", "10090"])'), + }), + name: "getTaxonomyNameReport", + outputSchema: z.any().describe("Taxonomy name report data"), + }, + async (input: { taxons: string[] }) => { + try { + logger.info( + `Getting taxonomy name report for taxons: ${input.taxons.join(", ")}` + ); + const result = await ncbiClient.getTaxonomyNameReport(input.taxons); + return result; + } catch (error) { + logger.error(`Error getting taxonomy name report: ${error}`); + throw new Error( + `Failed to get taxonomy name report: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get BioSample report by accessions + */ +export const getBiosampleReportTool = ai.defineTool( + { + description: "Get BioSample report for specific BioSample accessions", + inputSchema: z.object({ + accessions: z + .array(z.string()) + .describe( + 'Array of BioSample accessions (e.g., ["SAMN02981385", "SAMN00000001"])' + ), + }), + name: "getBiosampleReport", + outputSchema: z.any().describe("BioSample report data"), + }, + async (input: { accessions: string[] }) => { + try { + logger.info( + `Getting BioSample report for accessions: ${input.accessions.join(", ")}` + ); + const result = await ncbiClient.getBiosampleReport(input.accessions); + return result; + } catch (error) { + logger.error(`Error getting BioSample report: ${error}`); + throw new Error( + `Failed to get BioSample report: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +/** + * Tool to get organelle dataset report by accessions + */ +export const getOrganelleDatasetReportTool = ai.defineTool( + { + description: + "Get organelle dataset report for specific organelle accessions", + inputSchema: z.object({ + accessions: z.array(z.string()).describe("Array of organelle accessions"), + }), + name: "getOrganelleDatasetReport", + outputSchema: z.any().describe("Organelle dataset report data"), + }, + async (input: { accessions: string[] }) => { + try { + logger.info( + `Getting organelle dataset report for accessions: ${input.accessions.join(", ")}` + ); + const result = await ncbiClient.getOrganelleDatasetReport( + input.accessions + ); + return result; + } catch (error) { + logger.error(`Error getting organelle dataset report: ${error}`); + throw new Error( + `Failed to get organelle dataset report: ${error instanceof Error ? error.message : String(error)}` + ); + } + } +); + +// Export all NCBI tools as an array +export const ncbiTools = [ + getGenomeAnnotationReportTool, + getGenomeDatasetReportTool, + getGenomeSequenceReportsTool, + getGenomeByAssemblyNameDatasetReportTool, + getGenomeByBioprojectDatasetReportTool, + getGenomeByBiosampleDatasetReportTool, + getGenomeByTaxonDatasetReportTool, + getGeneByAccessionTool, + getGeneOrthologsTool, + getGeneByIdTool, + getGeneLinksTool, + getGeneByTaxonTool, + getGeneChromosomeSummaryTool, + getTaxonomyDatasetReportTool, + getTaxonomyNameReportTool, + getBiosampleReportTool, + getOrganelleDatasetReportTool, +]; diff --git a/genkit/src/server.ts b/genkit/src/server.ts new file mode 100644 index 00000000..8fdd90d1 --- /dev/null +++ b/genkit/src/server.ts @@ -0,0 +1,174 @@ +import express, { Request, Response } from "express"; +import cors from "cors"; +import dotenv from "dotenv"; +import path from "path"; +import multer from "multer"; +import fs from "fs"; +import { logger } from "@genkit-ai/core/logging"; +import { chatFlow } from "./index"; +import { FileSessionStore } from "./sessionStore"; +import crypto from "crypto"; + +// Extend Express Request with file property +declare module "express" { + interface Request { + file?: Express.Multer.File; + files?: + | { [fieldname: string]: Express.Multer.File[] } + | Express.Multer.File[]; + } +} + +// Load environment variables +dotenv.config(); + +// Create Express app +const app = express(); +// Remove X-Powered-By header for security +app.disable("x-powered-by"); +const port = process.env.PORT ? parseInt(process.env.PORT) : 3100; +const host = process.env.HOST || "localhost"; + +// Initialize session store for chat message history +const sessionStore = new FileSessionStore("./data/sessions"); + +// Configure multer for file uploads +const uploadDir = path.join(__dirname, "../data/uploads"); + +// Create uploads directory if it doesn't exist +if (!fs.existsSync(uploadDir)) { + fs.mkdirSync(uploadDir, { recursive: true }); +} + +const storage = multer.diskStorage({ + destination: ( + req: Request, + file: Express.Multer.File, + cb: (error: Error | null, destination: string) => void + ) => { + cb(null, uploadDir); + }, + filename: ( + req: Request, + file: Express.Multer.File, + cb: (error: Error | null, filename: string) => void + ) => { + // Use crypto for secure random values instead of Math.random + const uniqueSuffix = + Date.now() + "-" + crypto.randomBytes(6).toString("hex"); + cb(null, uniqueSuffix + "-" + file.originalname); + }, +}); + +// Set reasonable limits for security +const upload = multer({ + limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit + storage, +}); + +// Middleware +// Configure CORS with specific options for security +app.use( + cors({ + allowedHeaders: ["Content-Type", "Authorization"], + methods: ["GET", "POST"], + origin: process.env.ALLOWED_ORIGINS + ? process.env.ALLOWED_ORIGINS.split(",") + : "*", + }) +); +// Set content-length limit for JSON payloads +app.use(express.json({ limit: "1mb" })); + +// Health check endpoint +app.get("/health", (req: Request, res: Response) => { + res.json({ status: "ok", timestamp: new Date().toISOString() }); +}); + +// Chat endpoint +app.post("/api/chat", async (req: Request, res: Response) => { + try { + const { message, session_id } = req.body; + + if (!message) { + return res.status(400).json({ error: "Message is required" }); + } + + // Generate or use the provided session ID + const sessionId = session_id || `session_${Date.now()}`; + + const response = await chatFlow({ message, session_id: sessionId }); + res.json({ response, sessionId }); + } catch (error) { + logger.error("Error in chat endpoint:", error); + res.status(500).json({ + details: error instanceof Error ? error.message : String(error), + error: "An error occurred processing your request", + }); + } +}); + +// File upload endpoint +app.post( + "/api/upload", + upload.single("file"), + async (req: Request, res: Response) => { + try { + if (!req.file) { + return res.status(400).json({ error: "No file uploaded" }); + } + + const sessionId = req.body.sessionId || `session_${Date.now()}`; + + // Get or create the session + let session = await sessionStore.get(sessionId); + if (!session) { + session = await sessionStore.create(sessionId); + } + + // Create file metadata + const fileData = { + filename: req.file.filename, + mimetype: req.file.mimetype, + originalName: req.file.originalname, + path: req.file.path, + size: req.file.size, + }; + + // Add a system message about the file upload + session.messages.push({ + content: `Uploaded file: ${req.file.originalname}`, + role: "user", + }); + + // Save the updated session + await sessionStore.save(sessionId, session); + + res.json({ + file: fileData, + sessionId, + success: true, + }); + } catch (error) { + logger.error("Error in upload endpoint:", error); + res.status(500).json({ + error: error instanceof Error ? error.message : String(error), + success: false, + }); + } + } +); + +// Serve static files from the data directory +app.use("/data", express.static(path.join(__dirname, "../data"))); + +// Start the server +app.listen(port, host, () => { + logger.info(`BRC Analytics GenKit server running at http://${host}:${port}`); + logger.info(`Health check: http://${host}:${port}/health`); + logger.info(`Chat API: http://${host}:${port}/api/chat (POST)`); + logger.info(`Upload API: http://${host}:${port}/api/upload (POST)`); +}); + +// Export the app for testing +export default app; diff --git a/genkit/src/sessionStore.ts b/genkit/src/sessionStore.ts new file mode 100644 index 00000000..53a737dd --- /dev/null +++ b/genkit/src/sessionStore.ts @@ -0,0 +1,113 @@ +import fs from "fs"; +import path from "path"; +import { Session } from "./types"; + +/** + * FileSessionStore manages chat sessions using the filesystem + */ +export class FileSessionStore { + private baseDir: string; + + constructor(baseDir: string) { + this.baseDir = baseDir; + // Ensure the directory exists + if (!fs.existsSync(baseDir)) { + fs.mkdirSync(baseDir, { recursive: true }); + } + } + + /** + * Get a session by ID + * @param sessionId - The unique identifier of the session to retrieve + * @returns A Promise resolving to the Session object if found, or null if not found + */ + async get(sessionId: string): Promise { + const sessionPath = path.join(this.baseDir, `${sessionId}.json`); + + try { + if (fs.existsSync(sessionPath)) { + const data = fs.readFileSync(sessionPath, "utf8"); + return JSON.parse(data) as Session; + } + } catch (error) { + console.error(`Error reading session ${sessionId}:`, error); + } + + return null; + } + + /** + * Create a new session or update an existing one + * @param sessionId - The unique identifier of the session to save + * @param session - The session object to save + * @returns A Promise that resolves when the session is saved + */ + async save(sessionId: string, session: Session): Promise { + const sessionPath = path.join(this.baseDir, `${sessionId}.json`); + + try { + // Update the timestamp + session.updatedAt = Date.now(); + + // Write the session to disk + fs.writeFileSync(sessionPath, JSON.stringify(session, null, 2)); + } catch (error) { + console.error(`Error saving session ${sessionId}:`, error); + throw error; + } + } + + /** + * Create a new session + * @param sessionId - The unique identifier for the new session + * @returns A Promise resolving to the newly created Session object + */ + async create(sessionId: string): Promise { + const now = Date.now(); + const session: Session = { + createdAt: now, + id: sessionId, + messages: [], + updatedAt: now, + }; + + await this.save(sessionId, session); + return session; + } + + /** + * Delete a session + * @param sessionId - The unique identifier of the session to delete + * @returns A Promise resolving to true if the session was deleted, false otherwise + */ + async delete(sessionId: string): Promise { + const sessionPath = path.join(this.baseDir, `${sessionId}.json`); + + try { + if (fs.existsSync(sessionPath)) { + fs.unlinkSync(sessionPath); + return true; + } + } catch (error) { + console.error(`Error deleting session ${sessionId}:`, error); + } + + return false; + } + + /** + * List all sessions + * @returns A Promise resolving to an array of session IDs + */ + async list(): Promise { + try { + const files = fs.readdirSync(this.baseDir); + return files + .filter((file) => file.endsWith(".json")) + .map((file) => file.replace(".json", "")); + } catch (error) { + console.error("Error listing sessions:", error); + return []; + } + } +} diff --git a/genkit/src/types.ts b/genkit/src/types.ts new file mode 100644 index 00000000..5e51c1a5 --- /dev/null +++ b/genkit/src/types.ts @@ -0,0 +1,139 @@ +// Define types for BRC Analytics data + +// Session type for chat history +export interface Session { + createdAt: number; + id: string; + messages: Array<{ content: string; role: string }>; + updatedAt: number; +} + +// Organism type based on organisms.json +export interface Organism { + assemblyCount: number; + assemblyTaxonomyIds: string[]; + commonName: string | null; + genomes: Genome[]; +} + +// Genome type for organism data +export interface Genome { + accession: string; + annotationStatus: string | null; + chromosomes: Record | null; + commonName: string | null; + coverage: string; + gcPercent: number; + geneModelUrl: string; + isRef: string; + length: number; + level: string; + lineageTaxonomyIds: string[]; + ncbiTaxonomyId: string; + otherTaxa: Record | null; + ploidy: string[]; + priority: Record | null; + priorityPathogenName: string | null; + scaffoldCount: number; + scaffoldL50: number; + scaffoldN50: number; + speciesTaxonomyId: string; + strainName: string; + taxonomicGroup: string[]; + taxonomicLevelClass: string; + taxonomicLevelDomain: string; + taxonomicLevelFamily: string; + taxonomicLevelGenus: string; + taxonomicLevelOrder: string; + taxonomicLevelPhylum: string; + taxonomicLevelSpecies: string; + taxonomicLevelStrain: string; +} + +// Assembly type based on assemblies.json +export interface Assembly { + accession: string; + annotationStatus: string | null; + chromosomes: Record | null; + commonName: string | null; + coverage: string; + gcPercent: number; + geneModelUrl: string; + isRef: string; + length: number; + level: string; + lineageTaxonomyIds: string[]; + ncbiTaxonomyId: string; + otherTaxa: Record | null; + ploidy: string[]; + priority: Record | null; + priorityPathogenName: string | null; + scaffoldCount: number; + scaffoldL50: number; + scaffoldN50: number; + speciesTaxonomyId: string; + strainName: string; + taxonomicGroup: string[]; + taxonomicLevelClass: string; + taxonomicLevelDomain: string; + taxonomicLevelFamily: string; + taxonomicLevelGenus: string; + taxonomicLevelOrder: string; + taxonomicLevelPhylum: string; + taxonomicLevelSpecies: string; + taxonomicLevelStrain: string; +} + +// Workflow type based on workflows.json +export interface Workflow { + description: string; + id: string; + name: string; + parameters: WorkflowParameter[]; + steps: WorkflowStep[]; + tags: string[]; + url?: string; + version: string; +} + +export interface WorkflowParameter { + default?: unknown; + description?: string; + id: string; + name: string; + required: boolean; + type: string; + url_spec?: WorkflowUrlSpec; + variable?: string; +} + +export interface WorkflowUrlSpec { + headers?: Record; + method: string; + url: string; +} + +export interface WorkflowStep { + description?: string; + id: string; + inputs: Record; + name: string; + outputs: Record; + tool_id: string; +} + +// Outbreak type based on outbreaks.json +export interface Outbreak { + description: string; + id: string; + name: string; + priority: string; + resources: OutbreakResource[]; + taxonomyId: string; +} + +export interface OutbreakResource { + title: string; + type: string; + url: string; +} diff --git a/genkit/tsconfig.json b/genkit/tsconfig.json new file mode 100644 index 00000000..0c76e502 --- /dev/null +++ b/genkit/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "outDir": "./dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.spec.ts"] +} diff --git a/package-lock.json b/package-lock.json index 45b18476..29e53e93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "next-mdx-remote": "^4.2.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-markdown": "^10.1.0", "react-window": "1.8.9", "rehype-raw": "^7.0.0", "rehype-react": "^7.2.0", @@ -62,6 +63,7 @@ "@types/uuid": "8.3.4", "@typescript-eslint/eslint-plugin": "^8.18.0", "babel-loader": "^9.2.1", + "concurrently": "^9.2.0", "csv-parse": "^5.6.0", "eslint": "^8.57.1", "eslint-config-next": "^14.2.28", @@ -3339,15 +3341,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/console/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3438,15 +3431,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/core/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -3693,15 +3677,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", @@ -3876,15 +3851,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/transform/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3945,15 +3911,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/types/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5004,16 +4961,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/dom/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5077,15 +5024,6 @@ "node": ">=8" } }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/jest-dom/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6744,15 +6682,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/babel-jest/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7458,6 +7387,78 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/concurrently": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.0.tgz", + "integrity": "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/conventional-changelog-angular": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", @@ -7649,15 +7650,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/create-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/create-jest/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9476,15 +9468,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -10321,6 +10304,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -10644,6 +10636,16 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/html-void-elements": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", @@ -11712,15 +11714,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-lib-report/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -11964,15 +11957,6 @@ } } }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-circus/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -12075,15 +12059,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12192,15 +12167,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-config/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -12285,15 +12251,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-diff/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -12391,15 +12348,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-each/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -12629,15 +12577,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-matcher-utils/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -12727,15 +12666,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-message-util/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -12864,15 +12794,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-resolve/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12948,15 +12869,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-runner/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13053,15 +12965,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-runtime/node_modules/jest-mock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", @@ -13150,15 +13053,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-snapshot/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -13278,15 +13172,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-util/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13359,15 +13244,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-validate/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -13456,15 +13332,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-watcher/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13492,30 +13359,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", @@ -19582,6 +19425,85 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-markdown/node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -20744,6 +20666,16 @@ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -20981,6 +20913,19 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -21441,6 +21386,21 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -21533,15 +21493,6 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/terser-webpack-plugin/node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -21556,21 +21507,6 @@ "node": ">= 10.13.0" } }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -21745,6 +21681,16 @@ "node": ">=12" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", diff --git a/package.json b/package.json index ccca1b05..89694971 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,11 @@ "lint-schema": "linkml-lint ./catalog/py_package/catalog_build/schema --validate --verbose", "gen-schema": "./catalog/schema/scripts/gen-schema.sh", "test-gen-python": "./catalog/schema/scripts/test-gen-python.sh", - "validate-catalog": "./catalog/schema/scripts/validate-catalog.sh" + "validate-catalog": "./catalog/schema/scripts/validate-catalog.sh", + "genkit:build": "cd genkit && npm run build", + "genkit:start": "cd genkit && npm start", + "genkit:dev": "cd genkit && npm run dev", + "dev:all": "concurrently --kill-others \"npm run genkit:dev\" \"npm run dev\"" }, "dependencies": { "@databiosphere/findable-ui": "^38.2.0", @@ -43,6 +47,7 @@ "next-mdx-remote": "^4.2.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-markdown": "^10.1.0", "react-window": "1.8.9", "rehype-raw": "^7.0.0", "rehype-react": "^7.2.0", @@ -77,6 +82,7 @@ "@types/uuid": "8.3.4", "@typescript-eslint/eslint-plugin": "^8.18.0", "babel-loader": "^9.2.1", + "concurrently": "^9.2.0", "csv-parse": "^5.6.0", "eslint": "^8.57.1", "eslint-config-next": "^14.2.28", diff --git a/public/main/biobuddy.png b/public/main/biobuddy.png new file mode 100644 index 00000000..cbece00b Binary files /dev/null and b/public/main/biobuddy.png differ diff --git a/site-config/brc-analytics/local/floating/floating.ts b/site-config/brc-analytics/local/floating/floating.ts index cff73a85..0244011c 100644 --- a/site-config/brc-analytics/local/floating/floating.ts +++ b/site-config/brc-analytics/local/floating/floating.ts @@ -2,15 +2,15 @@ import { ComponentConfig, FloatingConfig, } from "@databiosphere/findable-ui/lib/config/entities"; -import { StyledViewSupport } from "../../../../app/components/Support/components/ViewSupport/viewSupport.styles"; +import { MinimizableChat } from "../../../../app/components/Chat/components/MinimizableChat"; export const floating: FloatingConfig = { components: [ { - component: StyledViewSupport, + component: MinimizableChat, props: { - url: "https://docs.google.com/forms/d/e/1FAIpQLSd8f5hrd1-ECgPUbS5dL9njoU1nvCSN5ukykKk9mF6WAyTh6A/viewform?usp=sf_link", + initiallyMinimized: true, }, - } as ComponentConfig, + } as ComponentConfig, ], };