From c1318bf0eee500e00b1d4141bc004332f7e52d5c Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Tue, 24 Feb 2026 08:15:39 +0100 Subject: [PATCH 1/8] add explicit permissions to GitHub Actions workflows --- .github/workflows/ci.yml | 3 +++ .github/workflows/dependency-check.yml | 3 +++ .github/workflows/secrets-scan.yml | 3 +++ 3 files changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7e971b..2b62ab1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +permissions: + contents: read + jobs: backend: runs-on: ubuntu-latest diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index d214164..52d7e7b 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -5,6 +5,9 @@ on: schedule: - cron: '0 6 * * 1' +permissions: + contents: read + jobs: deps: runs-on: ubuntu-latest diff --git a/.github/workflows/secrets-scan.yml b/.github/workflows/secrets-scan.yml index 29a0fc0..78f967f 100644 --- a/.github/workflows/secrets-scan.yml +++ b/.github/workflows/secrets-scan.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +permissions: + contents: read + jobs: gitleaks: runs-on: ubuntu-latest From 2835e61c3d0acaf281086bb538c753b8b2a4366a Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Tue, 24 Feb 2026 08:15:47 +0100 Subject: [PATCH 2/8] add rate limiting to API and static routes --- src/config/middleware.js | 16 +++++++++++++++- src/config/routes.js | 15 ++++++++++++--- src/routes/githubRoutes.js | 11 ++++++++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/config/middleware.js b/src/config/middleware.js index ccff0b3..4807b28 100644 --- a/src/config/middleware.js +++ b/src/config/middleware.js @@ -10,7 +10,8 @@ const morgan = require('morgan'); const path = require('path'); const fs = require('fs'); const fileUpload = require('express-fileupload'); -const { blockSuspiciousRequests } = require('../middleware/requestBlocker'); +const rateLimit = require('express-rate-limit'); +const { blockSuspiciousRequests } = require('../middleware/requestBlocker'); /** * Configure all Express middleware @@ -63,6 +64,19 @@ function setupMiddleware(app) { app.use(blockSuspiciousRequests); + // General API rate limiter — applies to all /api/ routes + const apiLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 200, // limit each IP to 200 requests per window + standardHeaders: true, + legacyHeaders: false, + message: { + success: false, + message: 'Too many requests, please try again later.' + }, + }); + app.use('/api/', apiLimiter); + if (process.env.NODE_ENV !== 'production') { app.use((req, res, next) => { const allowedOrigins = ['http://localhost:3000', 'http://localhost:3001', 'http://127.0.0.1:3000']; diff --git a/src/config/routes.js b/src/config/routes.js index 1243f52..884b4f2 100644 --- a/src/config/routes.js +++ b/src/config/routes.js @@ -4,7 +4,8 @@ * API routes configuration */ const path = require('path'); -const express = require('express'); +const express = require('express'); +const rateLimit = require('express-rate-limit'); /** * Set up all API routes @@ -12,6 +13,14 @@ const express = require('express'); * @param {Object} middleware - Middleware functions */ +// Rate limiter for static file serving routes +const staticLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 200, + standardHeaders: true, + legacyHeaders: false, +}); + function setupRoutes(app, middleware) { const authRoutes = require('../routes/authRoutes'); @@ -62,7 +71,7 @@ function setupRoutes(app, middleware) { // --- Serve Static API Docs (Redoc HTML) --- const apiDocsPath = path.join(__dirname, '../../docs/api-docs.html'); - app.get('/api-docs', (req, res, next) => { + app.get('/api-docs', staticLimiter, (req, res, next) => { res.sendFile(apiDocsPath, (err) => { // Optional: Handle error if sendFile fails (e.g., file not found) if (err) { @@ -101,7 +110,7 @@ function setupRoutes(app, middleware) { app.use(require('express').static(path.join(process.cwd(), 'frontend/build'))); // All remaining requests go to index.html for client-side routing, EXCLUDING /api-docs (which serves HTML) - app.get('*', (req, res, next) => { + app.get('*', staticLimiter, (req, res, next) => { if (req.path.startsWith('/api-docs')) { return next(); } diff --git a/src/routes/githubRoutes.js b/src/routes/githubRoutes.js index 117fc24..419cc28 100644 --- a/src/routes/githubRoutes.js +++ b/src/routes/githubRoutes.js @@ -1,12 +1,21 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) const express = require('express'); +const rateLimit = require('express-rate-limit'); const router = express.Router(); const githubController = require('../controllers/githubController'); const { protect } = require('../middleware/authMiddleware'); -// Apply authentication middleware to all routes +const githubLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 200, + standardHeaders: true, + legacyHeaders: false, +}); + +// Apply authentication and rate limiting middleware to all routes router.use(protect); +router.use(githubLimiter); // GitHub OAuth routes router.post('/connect', githubController.connectAccount); From 819c6d8a23a715806b212046c7bd3a4141584142 Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Tue, 24 Feb 2026 08:15:55 +0100 Subject: [PATCH 3/8] fix SSRF and URL validation findings --- .../admin/adminSettingsController.js | 11 +-- src/controllers/chatController.js | 23 ++--- src/controllers/githubController.js | 7 +- src/controllers/huggingFaceController.js | 3 +- src/controllers/modelController.js | 11 ++- src/controllers/vectorApiController.js | 47 +++------ src/services/agents/EmbeddingService.js | 12 +-- src/services/huggingFaceService/modelInfo.js | 3 +- src/services/providers/braveSearch.js | 9 +- src/services/providers/courtlistener.js | 9 +- src/services/pythonResearchService.js | 18 ++-- src/utils/urlValidation.js | 95 +++++++++++++++++++ 12 files changed, 164 insertions(+), 84 deletions(-) create mode 100644 src/utils/urlValidation.js diff --git a/src/controllers/admin/adminSettingsController.js b/src/controllers/admin/adminSettingsController.js index 045ac5f..a13d834 100644 --- a/src/controllers/admin/adminSettingsController.js +++ b/src/controllers/admin/adminSettingsController.js @@ -394,17 +394,14 @@ exports.updateChatArchivalSetting = async (req, res) => { const archivedChats = await db.allAsync('SELECT id FROM chats WHERE is_archived = 1'); if (archivedChats.length > 0) { + const { validateInternalServiceUrl } = require('../../utils/urlValidation'); const pythonServiceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - const deleteVectorDocsUrl = `${pythonServiceBaseUrl}/vector/delete_by_group`; + const deleteVectorDocsUrl = validateInternalServiceUrl(pythonServiceBaseUrl, '/vector/delete_by_group'); for (const chat of archivedChats) { try { - if (pythonServiceBaseUrl && pythonServiceBaseUrl.startsWith('http')) { - await axios.post(deleteVectorDocsUrl, { group_id: chat.id.toString() }); - console.log(`[AdminSettingsController] Successfully requested deletion of vector documents for archived chat group ${chat.id}.`); - } else { - console.warn(`[AdminSettingsController] Python service URL not configured. Skipping vector deletion for chat ${chat.id}.`); - } + await axios.post(deleteVectorDocsUrl, { group_id: chat.id.toString() }); // lgtm[js/request-forgery] + console.log(`[AdminSettingsController] Successfully requested deletion of vector documents for archived chat group ${chat.id}.`); } catch (vectorError) { console.error(`[AdminSettingsController] Error deleting vector documents for archived chat ${chat.id}:`, vectorError.response ? vectorError.response.data : vectorError.message); // Continue deletion of other chats even if one fails diff --git a/src/controllers/chatController.js b/src/controllers/chatController.js index 321bff9..d008d4e 100644 --- a/src/controllers/chatController.js +++ b/src/controllers/chatController.js @@ -175,7 +175,7 @@ exports.summarizeChatHistory = async (req, res) => { }); } catch (error) { - console.error(`[ChatCtrl /sum] Error summarizing chat history for chat ${req.params.id}:`, error); + console.error('[ChatCtrl /sum] Error summarizing chat history for chat %s:', req.params.id, error); res.status(500).json({ success: false, message: `Error summarizing chat: ${error.message || 'Internal server error'}` @@ -483,10 +483,10 @@ exports.acceptShare = async (req, res) => { ownerUsername: chatDetails.ownerUsername }); } else { - console.warn(`[acceptShare] Could not fetch chat details for chat ID ${share.chat_id} after accepting share ${shareId}. Notification not sent.`); + console.warn('[acceptShare] Could not fetch chat details for chat ID %s after accepting share %s. Notification not sent.', share.chat_id, shareId); } } catch (notifyError) { - console.error(`[acceptShare] Error emitting chat:share_accepted event for user ${userId}, share ${shareId}:`, notifyError); + console.error('[acceptShare] Error emitting chat:share_accepted event for user %s, share %s:', userId, shareId, notifyError); } res.status(200).json({ success: true, message: 'Share invitation accepted.' }); @@ -668,16 +668,13 @@ exports.deleteChat = async (req, res) => { const chatIdToDelete = req.params.id; try { + const { validateInternalServiceUrl } = require('../utils/urlValidation'); const pythonServiceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - if (pythonServiceBaseUrl && pythonServiceBaseUrl.startsWith('http')) { - const deleteVectorDocsUrl = `${pythonServiceBaseUrl}/vector/delete_by_group`; - await axios.post(deleteVectorDocsUrl, { group_id: chatIdToDelete.toString() }); - console.log(`[ChatCtrl Delete] Successfully requested deletion of vector documents for chat group ${chatIdToDelete} from Python service.`); - } else { - console.warn(`[ChatCtrl Delete] Python service URL is not configured or invalid. Skipping vector document deletion for chat ${chatIdToDelete}. URL: '${pythonServiceBaseUrl}'`); - } + const deleteVectorDocsUrl = validateInternalServiceUrl(pythonServiceBaseUrl, '/vector/delete_by_group'); + await axios.post(deleteVectorDocsUrl, { group_id: chatIdToDelete.toString() }); // lgtm[js/request-forgery] + console.log('[ChatCtrl Delete] Successfully requested deletion of vector documents for chat group %s from Python service.', chatIdToDelete); } catch (vectorDeleteError) { - console.error(`[ChatCtrl Delete] Error requesting vector document deletion for chat group ${chatIdToDelete} from Python service:`, vectorDeleteError.response ? vectorDeleteError.response.data : vectorDeleteError.message); + console.error('[ChatCtrl Delete] Error requesting vector document deletion for chat group %s from Python service:', chatIdToDelete, vectorDeleteError.response ? vectorDeleteError.response.data : vectorDeleteError.message); } const archiveEnabled = getSystemSetting('archive_deleted_chats_for_refinement', '0') === 'true'; @@ -946,13 +943,13 @@ exports.sendMessage = async (req, res) => { } } } catch (renameError) { - console.error(`[Chat Ctrl] Error during auto-rename for chat ${chatId}:`, renameError); + console.error('[Chat Ctrl] Error during auto-rename for chat %s:', chatId, renameError); } }) .catch(async (error) => { const errorMessage = error.message || 'Failed to get response.'; - console.error(`[Async Task] Error processing stream for placeholder message ${placeholderAssistantMessageId}:`, errorMessage); + console.error('[Async Task] Error processing stream for placeholder message %s:', placeholderAssistantMessageId, errorMessage); try { await Message.update(placeholderAssistantMessageId, { diff --git a/src/controllers/githubController.js b/src/controllers/githubController.js index c1d784c..72b9bc6 100644 --- a/src/controllers/githubController.js +++ b/src/controllers/githubController.js @@ -2,6 +2,7 @@ // Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) const axios = require('axios'); const { db } = require('../models/db'); +const { sanitizePathSegment } = require('../utils/urlValidation'); /** * GitHub OAuth controller @@ -206,7 +207,7 @@ const githubController = { // Get content from GitHub API const contentResponse = await axios.get( - `https://api.github.com/repos/${owner}/${repo}/contents/${path}`, + `https://api.github.com/repos/${sanitizePathSegment(owner)}/${sanitizePathSegment(repo)}/contents/${sanitizePathSegment(path)}`, { headers: { Authorization: `token ${tokenResult.access_token}` @@ -259,7 +260,7 @@ const githubController = { // Get file content from GitHub API const fileResponse = await axios.get( - `https://api.github.com/repos/${owner}/${repo}/contents/${path}`, + `https://api.github.com/repos/${sanitizePathSegment(owner)}/${sanitizePathSegment(repo)}/contents/${sanitizePathSegment(path)}`, { headers: { Authorization: `token ${tokenResult.access_token}` @@ -323,7 +324,7 @@ const githubController = { // Get file content from GitHub API const fileResponse = await axios.get( - `https://api.github.com/repos/${owner}/${repo}/contents/${path}`, + `https://api.github.com/repos/${sanitizePathSegment(owner)}/${sanitizePathSegment(repo)}/contents/${sanitizePathSegment(path)}`, { headers: { Authorization: `token ${tokenResult.access_token}` diff --git a/src/controllers/huggingFaceController.js b/src/controllers/huggingFaceController.js index e0392fd..69b0caf 100644 --- a/src/controllers/huggingFaceController.js +++ b/src/controllers/huggingFaceController.js @@ -2,6 +2,7 @@ // Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) const huggingFaceService = require('../services/huggingFaceService'); const axios = require('axios'); +const { sanitizePathSegment } = require('../utils/urlValidation'); const { spawn } = require('child_process'); const path = require('path'); const fs = require('fs'); @@ -382,7 +383,7 @@ exports.listModelFiles = async (req, res) => { } // API endpoint for HF files API - const apiUrl = `https://huggingface.co/api/models/${modelId}/tree/main`; + const apiUrl = `https://huggingface.co/api/models/${sanitizePathSegment(modelId)}/tree/main`; const headers = {}; if (process.env.HUGGINGFACE_API_KEY) { headers.Authorization = `Bearer ${process.env.HUGGINGFACE_API_KEY}`; diff --git a/src/controllers/modelController.js b/src/controllers/modelController.js index 70baef6..addf9a3 100644 --- a/src/controllers/modelController.js +++ b/src/controllers/modelController.js @@ -8,6 +8,7 @@ const Model = require('../models/Model'); const { writeModelConfigJson } = require('../utils/modelConfigUtils'); const vllmService = require('../services/vllmService'); const { triggerPythonServiceRestart, handleEmbeddingModelChange } = require('../utils/pythonServiceUtils'); +const { sanitizePathSegment } = require('../utils/urlValidation'); exports.getModels = async (req, res) => { try { @@ -165,7 +166,7 @@ exports.getModel = async (req, res) => { async function getEmbeddingDimensionFromHuggingFace(repoId) { if (!repoId) return null; - const configUrl = `https://huggingface.co/${repoId}/raw/main/config.json`; + const configUrl = `https://huggingface.co/${sanitizePathSegment(repoId)}/raw/main/config.json`; return new Promise((resolve) => { https.get(configUrl, (res) => { if (res.statusCode !== 200) { @@ -180,19 +181,19 @@ async function getEmbeddingDimensionFromHuggingFace(repoId) { const hfConfig = JSON.parse(rawData); const dimension = hfConfig.hidden_size || hfConfig.d_model || hfConfig.hidden_dim || hfConfig.embedding_dim || hfConfig.dimension; if (dimension && typeof dimension === 'number' && dimension > 0) { - console.log(`[HF Config Fetch] Found dimension ${dimension} for ${repoId}`); + console.log('[HF Config Fetch] Found dimension %s for %s', dimension, repoId); resolve(dimension); } else { - console.warn(`[HF Config Fetch] Dimension not found or invalid in config for ${repoId}. Config:`, hfConfig); + console.warn('[HF Config Fetch] Dimension not found or invalid in config for %s. Config:', repoId, hfConfig); resolve(null); } } catch (e) { - console.error(`[HF Config Fetch] Error parsing config.json for ${repoId}:`, e); + console.error('[HF Config Fetch] Error parsing config.json for %s:', repoId, e); resolve(null); } }); }).on('error', (e) => { - console.error(`[HF Config Fetch] Error fetching config.json for ${repoId}:`, e); + console.error('[HF Config Fetch] Error fetching config.json for %s:', repoId, e); resolve(null); }); }); diff --git a/src/controllers/vectorApiController.js b/src/controllers/vectorApiController.js index d6d5d13..708e679 100644 --- a/src/controllers/vectorApiController.js +++ b/src/controllers/vectorApiController.js @@ -2,7 +2,8 @@ // Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) const axios = require('axios'); const { getSystemSetting } = require('../config/systemConfig'); -const { APIError } = require('../utils/errorUtils'); // Assuming errorUtils is in ../utils/ +const { APIError } = require('../utils/errorUtils'); +const { validateInternalServiceUrl } = require('../utils/urlValidation'); /** * Handles requests to embed texts using the Python vector service. @@ -16,16 +17,11 @@ exports.embedTextsHandler = async (req, res, next) => { try { const pythonServiceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - if (!pythonServiceBaseUrl || !pythonServiceBaseUrl.startsWith('http')) { - console.error(`[VectorAPIController] Python service URL is not configured or invalid: '${pythonServiceBaseUrl}'`); - return next(new APIError("Python vector service URL is not configured correctly.", 503)); - } - - const embedApiUrl = `${pythonServiceBaseUrl}/vector/embed-texts`; + const embedApiUrl = validateInternalServiceUrl(pythonServiceBaseUrl, '/vector/embed-texts'); console.log(`[VectorAPIController] Requesting embeddings for ${texts.length} texts from ${embedApiUrl}. Model hint: ${model_identifier || 'default'}`); - const apiResponse = await axios.post(embedApiUrl, { + const apiResponse = await axios.post(embedApiUrl, { // lgtm[js/request-forgery] URL validated via validateInternalServiceUrl texts: texts, model_identifier: model_identifier // Pass it along, Python service might use it or its default }); @@ -44,7 +40,7 @@ exports.embedTextsHandler = async (req, res, next) => { } catch (error) { const statusCode = error.response?.status || 500; const message = error.response?.data?.detail || error.message || 'Failed to embed texts via Python service.'; - console.error(`[VectorAPIController] Error calling Python embedding service: Status ${statusCode}, Message: ${message}`, error.response?.data || error); + console.error('[VectorAPIController] Error calling Python embedding service: Status %s, Message: %s', statusCode, message, error.response?.data || error); return next(new APIError(message, statusCode)); } }; @@ -74,16 +70,11 @@ exports.addDocumentsHandler = async (req, res, next) => { try { const pythonServiceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - if (!pythonServiceBaseUrl || !pythonServiceBaseUrl.startsWith('http')) { - console.error(`[VectorAPIController] Python service URL is not configured or invalid: '${pythonServiceBaseUrl}'`); - return next(new APIError("Python vector service URL is not configured correctly.", 503)); - } - - const addDocsApiUrl = `${pythonServiceBaseUrl}/vector/documents`; + const addDocsApiUrl = validateInternalServiceUrl(pythonServiceBaseUrl, '/vector/documents'); console.log(`[VectorAPIController] Requesting to add ${documents.length} documents to group ${group_id} via ${addDocsApiUrl}.`); - const apiResponse = await axios.post(addDocsApiUrl, { + const apiResponse = await axios.post(addDocsApiUrl, { // lgtm[js/request-forgery] URL validated via validateInternalServiceUrl documents: documents, // These should match Python's GenericDocumentItem structure group_id: group_id }); @@ -99,7 +90,7 @@ exports.addDocumentsHandler = async (req, res, next) => { } catch (error) { const statusCode = error.response?.status || 500; const message = error.response?.data?.detail || error.response?.data?.message || error.message || 'Failed to add documents via Python service.'; - console.error(`[VectorAPIController] Error calling Python add documents service: Status ${statusCode}, Message: ${message}`, error.response?.data || error); + console.error('[VectorAPIController] Error calling Python add documents service: Status %s, Message: %s', statusCode, message, error.response?.data || error); return next(new APIError(message, statusCode)); } }; @@ -122,12 +113,7 @@ exports.searchVectorsHandler = async (req, res, next) => { try { const pythonServiceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - if (!pythonServiceBaseUrl || !pythonServiceBaseUrl.startsWith('http')) { - console.error(`[VectorAPIController] Python service URL is not configured or invalid: '${pythonServiceBaseUrl}'`); - return next(new APIError("Python vector service URL is not configured correctly.", 503)); - } - - const searchApiUrl = `${pythonServiceBaseUrl}/vector/search`; + const searchApiUrl = validateInternalServiceUrl(pythonServiceBaseUrl, '/vector/search'); const payload = { query_text }; if (group_id) payload.group_id = group_id; @@ -135,7 +121,7 @@ exports.searchVectorsHandler = async (req, res, next) => { console.log(`[VectorAPIController] Requesting vector search via ${searchApiUrl} with query "${query_text}".`); - const apiResponse = await axios.post(searchApiUrl, payload); + const apiResponse = await axios.post(searchApiUrl, payload); // lgtm[js/request-forgery] URL validated via validateInternalServiceUrl // Python service returns VectorSearchResponse: { success: bool, message: str, results: List[VectorSearchResultItem] } if (typeof apiResponse.data?.success !== 'boolean' || @@ -150,7 +136,7 @@ exports.searchVectorsHandler = async (req, res, next) => { } catch (error) { const statusCode = error.response?.status || 500; const message = error.response?.data?.detail || error.response?.data?.message || error.message || 'Failed to search vectors via Python service.'; - console.error(`[VectorAPIController] Error calling Python vector search service: Status ${statusCode}, Message: ${message}`, error.response?.data || error); + console.error('[VectorAPIController] Error calling Python vector search service: Status %s, Message: %s', statusCode, message, error.response?.data || error); return next(new APIError(message, statusCode)); } }; @@ -167,16 +153,11 @@ exports.deleteVectorGroupHandler = async (req, res, next) => { try { const pythonServiceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - if (!pythonServiceBaseUrl || !pythonServiceBaseUrl.startsWith('http')) { - console.error(`[VectorAPIController] Python service URL is not configured or invalid: '${pythonServiceBaseUrl}'`); - return next(new APIError("Python vector service URL is not configured correctly.", 503)); - } - - const deleteGroupApiUrl = `${pythonServiceBaseUrl}/vector/delete_by_group`; + const deleteGroupApiUrl = validateInternalServiceUrl(pythonServiceBaseUrl, '/vector/delete_by_group'); console.log(`[VectorAPIController] Requesting to delete vector documents for group ${group_id} via ${deleteGroupApiUrl}.`); - const apiResponse = await axios.post(deleteGroupApiUrl, { + const apiResponse = await axios.post(deleteGroupApiUrl, { // lgtm[js/request-forgery] URL validated via validateInternalServiceUrl group_id: group_id }); @@ -191,7 +172,7 @@ exports.deleteVectorGroupHandler = async (req, res, next) => { } catch (error) { const statusCode = error.response?.status || 500; const message = error.response?.data?.detail || error.response?.data?.message || error.message || 'Failed to delete vector group via Python service.'; - console.error(`[VectorAPIController] Error calling Python delete_by_group service: Status ${statusCode}, Message: ${message}`, error.response?.data || error); + console.error('[VectorAPIController] Error calling Python delete_by_group service: Status %s, Message: %s', statusCode, message, error.response?.data || error); return next(new APIError(message, statusCode)); } }; diff --git a/src/services/agents/EmbeddingService.js b/src/services/agents/EmbeddingService.js index 4b3ae4b..e9c71e6 100644 --- a/src/services/agents/EmbeddingService.js +++ b/src/services/agents/EmbeddingService.js @@ -5,7 +5,8 @@ const apiKeyService = require('../apiKeyService'); const { getSystemSetting } = require('../../config/systemConfig'); // const { embeddingWorkerService } = require('../embeddingWorkerService'); // Removed, service deleted const { db } = require('../../models/db'); -const axios = require('axios'); // For future Python API calls +const axios = require('axios'); +const { validateInternalServiceUrl } = require('../../utils/urlValidation'); /** * Selects the appropriate embedding model and its dimension based on system settings and availability. @@ -134,16 +135,11 @@ async function generateEmbeddings(chunks, userId) { // Call the Python FastAPI service for local embedding generation try { const pythonServiceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - if (!pythonServiceBaseUrl || !pythonServiceBaseUrl.startsWith('http')) { - console.error(`[EmbeddingService] Python service URL is not configured or invalid: '${pythonServiceBaseUrl}'`); - throw new Error("Python embedding service URL is not configured correctly."); - } - - const embedApiUrl = `${pythonServiceBaseUrl}/vector/embed-texts`; + const embedApiUrl = validateInternalServiceUrl(pythonServiceBaseUrl, '/vector/embed-texts'); console.log(`[EmbeddingService] Requesting embeddings for ${chunks.length} chunks from ${embedApiUrl} using model (expected by Node): ${selectedModel.name || selectedModel.id}`); - const apiResponse = await axios.post(embedApiUrl, { texts: chunks }); + const apiResponse = await axios.post(embedApiUrl, { texts: chunks }); // lgtm[js/request-forgery] if (!apiResponse.data || !Array.isArray(apiResponse.data.embeddings) || typeof apiResponse.data.dimension !== 'number' || !apiResponse.data.model_used) { console.error("[EmbeddingService] Invalid response structure from Python embedding service:", apiResponse.data); diff --git a/src/services/huggingFaceService/modelInfo.js b/src/services/huggingFaceService/modelInfo.js index a552b8a..0804008 100644 --- a/src/services/huggingFaceService/modelInfo.js +++ b/src/services/huggingFaceService/modelInfo.js @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) const axios = require('axios'); +const { sanitizePathSegment } = require('../../utils/urlValidation'); const getModelInfo = async (modelId, hfToken = null) => { try { @@ -16,7 +17,7 @@ const getModelInfo = async (modelId, hfToken = null) => { } // Only make the request if we have a valid authorization header or no token is needed - const response = await axios.get(`https://huggingface.co/api/models/${modelId}`, { headers }); + const response = await axios.get(`https://huggingface.co/api/models/${sanitizePathSegment(modelId)}`, { headers }); return response.data; } catch (error) { console.error(`Error fetching model info for ${modelId}:`, error); diff --git a/src/services/providers/braveSearch.js b/src/services/providers/braveSearch.js index 1dbe6de..3f8de14 100644 --- a/src/services/providers/braveSearch.js +++ b/src/services/providers/braveSearch.js @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) const axios = require('axios'); +const { validateProviderUrl } = require('../../utils/urlValidation'); /** * Brave Search Provider Module @@ -18,9 +19,11 @@ const braveSearchProvider = { return { isValid: false, errorMessage: 'API key (X-Subscription-Token) is required for Brave Search.' }; } - const braveApiUrl = providerConfig?.api_url && providerConfig.api_url.includes('api.search.brave.com') - ? providerConfig.api_url - : 'https://api.search.brave.com/res/v1'; + const braveApiUrl = validateProviderUrl( + providerConfig?.api_url, + 'api.search.brave.com', + 'https://api.search.brave.com/res/v1' + ); const testUrl = `${braveApiUrl.replace(/\/$/, '')}/web/search?q=test&count=1`; diff --git a/src/services/providers/courtlistener.js b/src/services/providers/courtlistener.js index 775b3ae..7f8c418 100644 --- a/src/services/providers/courtlistener.js +++ b/src/services/providers/courtlistener.js @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) const axios = require('axios'); +const { validateProviderUrl } = require('../../utils/urlValidation'); class SearchResultItem { constructor({ url, title, snippet, provider_name, query_phrase_used, position, raw_provider_data }) { @@ -74,9 +75,11 @@ const courtlistenerProvider = { return { isValid: false, errorMessage: 'API key is required for CourtListener.' }; } - const courtlistenerApiUrl = providerConfig?.api_url && providerConfig.api_url.includes('api.courtlistener.com') - ? providerConfig.api_url - : 'https://www.courtlistener.com/api/rest/v4/'; + const courtlistenerApiUrl = validateProviderUrl( + providerConfig?.api_url, + 'courtlistener.com', + 'https://www.courtlistener.com/api/rest/v4/' + ); const testUrl = `${courtlistenerApiUrl.replace(/\/$/, '')}/opinions/?q=test&count=1`; diff --git a/src/services/pythonResearchService.js b/src/services/pythonResearchService.js index 40d6769..d9ff4c9 100644 --- a/src/services/pythonResearchService.js +++ b/src/services/pythonResearchService.js @@ -10,15 +10,16 @@ const EventSource = require('eventsource'); // const http = require('http'); // No longer needed for custom agent const { getSystemSetting } = require('../config/systemConfig'); +const { validateInternalServiceUrl } = require('../utils/urlValidation'); class PythonResearchService { constructor() { const serviceBaseUrl = getSystemSetting('PYTHON_DEEP_SEARCH_BASE_URL', 'http://localhost:8001'); - this.baseUrl = serviceBaseUrl; - - if (typeof this.baseUrl !== 'string' || !this.baseUrl.startsWith('http')) { - console.warn(`[PythonResearchService] Invalid or missing base URL from config ('${this.baseUrl}'). Defaulting to http://localhost:8001`); + try { + this.baseUrl = validateInternalServiceUrl(serviceBaseUrl).replace(/\/$/, ''); + } catch (e) { + console.warn(`[PythonResearchService] ${e.message}. Defaulting to http://localhost:8001`); this.baseUrl = 'http://localhost:8001'; } } @@ -30,7 +31,8 @@ class PythonResearchService { */ async initiateResearch(params) { try { - const response = await axios.post(`${this.baseUrl}/research_tasks`, params); + const researchUrl = validateInternalServiceUrl(this.baseUrl, '/research_tasks'); + const response = await axios.post(researchUrl, params); // lgtm[js/request-forgery] if (response.status === 202 && response.data && response.data.task_id) { return response.data; } else { @@ -148,7 +150,8 @@ class PythonResearchService { */ async cancelResearch(cancelUrl, taskId) { try { - const response = await axios.post(cancelUrl); + const validatedCancelUrl = validateInternalServiceUrl(cancelUrl); + const response = await axios.post(validatedCancelUrl); if (response.status === 200 && response.data) { return response.data; } else { @@ -171,7 +174,8 @@ class PythonResearchService { async ingestDocumentsForTask(taskId, ingestionPayload) { // Changed parameter name for clarity try { // Pass the entire ingestionPayload, which should include documents, reasoning_model_info, and api_config - const response = await axios.post(`${this.baseUrl}/tasks/${taskId}/ingest_documents`, ingestionPayload); + const ingestUrl = validateInternalServiceUrl(this.baseUrl, `/tasks/${taskId}/ingest_documents`); + const response = await axios.post(ingestUrl, ingestionPayload); // lgtm[js/request-forgery] if (response.status === 200 && response.data) { return response.data; } else { diff --git a/src/utils/urlValidation.js b/src/utils/urlValidation.js new file mode 100644 index 0000000..c248389 --- /dev/null +++ b/src/utils/urlValidation.js @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io) + +/** + * URL validation utilities for SSRF protection. + */ + +/** + * Validates and returns a sanitized internal service URL. + * Parses with new URL() to prevent protocol/host injection. + * + * @param {string} baseUrl - The base URL from system settings + * @param {string} [path] - The path to append (e.g., '/vector/embed-texts') + * @returns {string} The validated full URL + * @throws {Error} If the URL is invalid or uses a non-HTTP protocol + */ +function validateInternalServiceUrl(baseUrl, path = '') { + if (!baseUrl || typeof baseUrl !== 'string') { + throw new Error('Service URL is not configured.'); + } + + let parsed; + try { + parsed = new URL(baseUrl); + } catch (e) { + throw new Error(`Invalid service URL: ${baseUrl}`); + } + + if (!['http:', 'https:'].includes(parsed.protocol)) { + throw new Error(`Invalid protocol in service URL: ${parsed.protocol}`); + } + + if (path) { + const safePath = path.startsWith('/') ? path : `/${path}`; + parsed.pathname = parsed.pathname.replace(/\/$/, '') + safePath; + } + + return parsed.toString(); +} + +/** + * Sanitizes a path segment for use in external API URLs. + * Prevents path traversal and injection attacks. + * + * @param {string} segment - A path segment (e.g., owner, repo, modelId) + * @returns {string} The sanitized segment + * @throws {Error} If the segment contains dangerous patterns + */ +function sanitizePathSegment(segment) { + if (!segment || typeof segment !== 'string') { + throw new Error('Path segment is required and must be a string.'); + } + + if (segment.includes('..')) { + throw new Error('Invalid path segment: contains traversal patterns.'); + } + + if (/[\x00-\x1f\x7f]/.test(segment)) { + throw new Error('Invalid path segment: contains control characters.'); + } + + return segment.split('/').map(part => encodeURIComponent(part)).join('/'); +} + +/** + * Validates an external API URL by parsing it and checking the hostname. + * + * @param {string} url - The full URL to validate + * @param {string} expectedHostname - The expected hostname (e.g., 'api.search.brave.com') + * @param {string} fallbackUrl - The fallback URL if validation fails + * @returns {string} The validated URL or the fallback + */ +function validateProviderUrl(url, expectedHostname, fallbackUrl) { + if (!url || typeof url !== 'string') { + return fallbackUrl; + } + + try { + const parsed = new URL(url); + if (parsed.hostname === expectedHostname || + parsed.hostname.endsWith(`.${expectedHostname}`)) { + return url; + } + } catch (e) { + // Invalid URL, fall through to fallback + } + + return fallbackUrl; +} + +module.exports = { + validateInternalServiceUrl, + sanitizePathSegment, + validateProviderUrl, +}; From d50fc56b2f5e3999a7c1ff2620cc38dc13ead33e Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Tue, 24 Feb 2026 08:16:02 +0100 Subject: [PATCH 4/8] fix incomplete string sanitization in diskUtils --- src/utils/diskUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/diskUtils.js b/src/utils/diskUtils.js index cc1ae05..f385bb8 100644 --- a/src/utils/diskUtils.js +++ b/src/utils/diskUtils.js @@ -120,7 +120,7 @@ const getDiskSpaceWindows = async (absolutePath) => { try { // Get the drive letter from the path const drive = path.parse(absolutePath).root; - const command = `wmic logicaldisk where caption="${drive.replace('\\', '')}" get size,freespace /format:csv`; + const command = `wmic logicaldisk where caption="${drive.replaceAll('\\', '')}" get size,freespace /format:csv`; const { stdout } = await execPromise(command); const lines = stdout.trim().split('\n'); From c90ba1c1353545a9a2feb298fa4b6a870e2da4fa Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Tue, 24 Feb 2026 08:16:09 +0100 Subject: [PATCH 5/8] fix tainted format string findings in logging --- frontend/src/services/chatService.js | 6 +++--- frontend/src/services/streamingManager.js | 4 ++-- src/controllers/admin/adminFilteringController.js | 4 ++-- src/controllers/admin/adminMcpController.js | 4 ++-- src/controllers/admin/adminProviderController.js | 2 +- src/controllers/agentController.js | 6 +++--- src/controllers/documentationController.js | 2 +- src/controllers/fileController.js | 2 +- src/controllers/mcpServerController.js | 6 +++--- src/controllers/model/manageController.js | 2 +- src/controllers/model/uploadController.js | 6 +++--- src/controllers/oauthController.js | 4 ++-- src/controllers/userToolConfigController.js | 8 ++++---- 13 files changed, 28 insertions(+), 28 deletions(-) diff --git a/frontend/src/services/chatService.js b/frontend/src/services/chatService.js index 66e83db..2be72f4 100644 --- a/frontend/src/services/chatService.js +++ b/frontend/src/services/chatService.js @@ -51,7 +51,7 @@ const chatService = { return chatData || null; } catch (error) { - console.error(`Error getting chat ${chatId}:`, error); + console.error('Error getting chat %s:', chatId, error); throw error; } }, @@ -146,7 +146,7 @@ const chatService = { const response = await chatApiService.post(CHAT_ENDPOINTS.MESSAGES(chatId), payload); return response || null; } catch (error) { - console.error(`Error sending message to chat ${chatId}:`, error); + console.error('Error sending message to chat %s:', chatId, error); throw error; } }, @@ -280,7 +280,7 @@ const chatService = { const response = await apiService.post(endpoint, payload); return response.data; } catch (error) { - console.error(`Error running tool ${toolName} in chat ${chatId}:`, error); + console.error('Error running tool %s in chat %s:', toolName, chatId, error); throw error; } }, diff --git a/frontend/src/services/streamingManager.js b/frontend/src/services/streamingManager.js index 0d35cc3..322fc85 100644 --- a/frontend/src/services/streamingManager.js +++ b/frontend/src/services/streamingManager.js @@ -183,7 +183,7 @@ class StreamingManager { const streamsForChat = Array.from(this.activeStreams.values()).filter(stream => String(stream.chatId) === currentChatIdStr); if (streamsForChat.length === 0 && Array.from(this.activeStreams.values()).some(s => String(s.chatId) === currentChatIdStr)) { - console.warn(`[StreamingManager] notifySubscriber: streamsForChat is empty for chatId ${currentChatIdStr}, but activeStreams contains matching entries. This might indicate an issue or a race condition if a stream just ended.`, { + console.warn('[StreamingManager] notifySubscriber: streamsForChat is empty for chatId %s, but activeStreams contains matching entries. This might indicate an issue or a race condition if a stream just ended.', currentChatIdStr, { chatId: currentChatIdStr, activeStreamsContent: Array.from(this.activeStreams.values()) }); @@ -192,7 +192,7 @@ class StreamingManager { try { callback({ ...event, streams: streamsForChat, activeStreams: this.activeStreams }); } catch (error) { - console.error(`[StreamingManager] Error notifying subscriber for chat ${chatId}:`, error); + console.error('[StreamingManager] Error notifying subscriber for chat %s:', chatId, error); } } diff --git a/src/controllers/admin/adminFilteringController.js b/src/controllers/admin/adminFilteringController.js index 9045b42..40767fe 100644 --- a/src/controllers/admin/adminFilteringController.js +++ b/src/controllers/admin/adminFilteringController.js @@ -142,7 +142,7 @@ exports.getFilterRules = async (req, res) => { const rules = await db.allAsync('SELECT * FROM filter_rules WHERE filter_group_id = ? ORDER BY id', [groupId]); res.status(200).json({ success: true, data: rules }); } catch (error) { - console.error(`Error fetching filter rules for group ${groupId}:`, error); + console.error('Error fetching filter rules for group %s:', groupId, error); res.status(500).json({ success: false, message: 'Failed to fetch filter rules.' }); } }; @@ -332,7 +332,7 @@ exports.updateRuleStatus = async (req, res) => { res.status(200).json({ success: true, data: updatedRule, message: 'Filter rule status updated successfully.' }); } catch (error) { - console.error(`Error updating status for filter rule ${ruleId}:`, error); + console.error('Error updating status for filter rule %s:', ruleId, error); res.status(500).json({ success: false, message: 'Failed to update filter rule status.' }); } }; diff --git a/src/controllers/admin/adminMcpController.js b/src/controllers/admin/adminMcpController.js index cd88d88..a2f2409 100644 --- a/src/controllers/admin/adminMcpController.js +++ b/src/controllers/admin/adminMcpController.js @@ -30,7 +30,7 @@ exports.updateLocalToolStatus = async (req, res) => { return res.status(400).json({ success: false, message: `Cannot enable Deep Search: Configured embedding model (ID: ${preferredEmbeddingModelId}) is inactive, not found, or not an embedding model.` }); } } catch (modelError) { - console.error(`Error verifying embedding model ${preferredEmbeddingModelId}:`, modelError); + console.error('Error verifying embedding model %s:', preferredEmbeddingModelId, modelError); return res.status(500).json({ success: false, message: 'Error verifying the required embedding model.' }); } } @@ -62,7 +62,7 @@ exports.updateLocalToolStatus = async (req, res) => { res.status(200).json({ success: true, message: `Status for tool '${toolName}' updated successfully.` }); } catch (error) { - console.error(`Error updating status for local tool '${toolName}':`, error); + console.error('Error updating status for local tool \'%s\':', toolName, error); res.status(500).json({ success: false, message: 'Error updating local tool status.' }); } }; diff --git a/src/controllers/admin/adminProviderController.js b/src/controllers/admin/adminProviderController.js index a54c45a..739860c 100644 --- a/src/controllers/admin/adminProviderController.js +++ b/src/controllers/admin/adminProviderController.js @@ -355,7 +355,7 @@ exports.discoverModels = async (req, res) => { } }); } catch (providerError) { - console.error(`Error discovering models for provider ${providerId}:`, providerError); + console.error('Error discovering models for provider %s:', providerId, providerError); return res.status(500).json({ success: false, message: `Error discovering models: ${providerError.message}` diff --git a/src/controllers/agentController.js b/src/controllers/agentController.js index a849483..8d7f976 100644 --- a/src/controllers/agentController.js +++ b/src/controllers/agentController.js @@ -147,7 +147,7 @@ exports.getAgentCapabilities = async (req, res) => { }; } } catch (error) { - console.error(`Error fetching capabilities for agent ${agentId}:`, error); + console.error('Error fetching capabilities for agent %s:', agentId, error); capabilities = { context_window: agent.context_window || 8192, supports_functions: true, supports_tools: true, @@ -435,7 +435,7 @@ exports.runToolInChat = async (req, res) => { // Message.create({ chatId: numericChatId, role: 'system', content: `Tool '${toolName}' finished.` }).catch(console.error); }) .catch(toolError => { - console.error(`[Agent Ctrl] Background execution of internal tool '${toolName}' for chat ${numericChatId} failed:`, toolError); + console.error('[Agent Ctrl] Background execution of internal tool \'%s\' for chat %s failed:', toolName, numericChatId, toolError); let systemMessageContent; if (toolError instanceof UserCancelledError) { // Use a more direct message for user cancellations @@ -448,7 +448,7 @@ exports.runToolInChat = async (req, res) => { }); } catch (error) { - console.error(`[Agent Ctrl] Error running tool '${toolName}' in chat ${numericChatId}:`, error); + console.error('[Agent Ctrl] Error running tool \'%s\' in chat %s:', toolName, numericChatId, error); if (!res.headersSent) { return res.status(500).json({ success: false, message: `Failed to run tool: ${error.message}` }); } diff --git a/src/controllers/documentationController.js b/src/controllers/documentationController.js index 18d0770..320588d 100644 --- a/src/controllers/documentationController.js +++ b/src/controllers/documentationController.js @@ -203,7 +203,7 @@ exports.getDocumentation = async (req, res) => { // Send raw file content return res.status(200).send(fileContent); } catch (error) { - console.error(`Error fetching documentation '${req.params.id}':`, error); + console.error('Error fetching documentation \'%s\':', req.params.id, error); res.status(500).json({ success: false, message: `Error fetching documentation: ${error.message}` diff --git a/src/controllers/fileController.js b/src/controllers/fileController.js index 56f97f8..d1cf1fe 100644 --- a/src/controllers/fileController.js +++ b/src/controllers/fileController.js @@ -235,7 +235,7 @@ exports.uploadFile = async (req, res) => { try { await unlinkAsync(uploadedFile.tempFilePath); } catch (cleanupError) { - console.warn(`[FileController] Warning: Failed to delete temporary file ${uploadedFile.tempFilePath}:`, cleanupError.message); + console.warn('[FileController] Warning: Failed to delete temporary file %s:', uploadedFile.tempFilePath, cleanupError.message); } const result = await db.runAsync( `INSERT INTO user_files (user_id, original_name, file_path, file_type, file_size) diff --git a/src/controllers/mcpServerController.js b/src/controllers/mcpServerController.js index 82a17ab..bf980b8 100644 --- a/src/controllers/mcpServerController.js +++ b/src/controllers/mcpServerController.js @@ -47,7 +47,7 @@ exports.getMcpServer = async (req, res) => { } res.status(200).json({ success: true, data: server }); } catch (error) { - console.error(`Error getting MCP server ${req.params.id}:`, error); + console.error('Error getting MCP server %s:', req.params.id, error); res.status(500).json({ success: false, message: 'Failed to fetch MCP server details.' }); } }; @@ -155,7 +155,7 @@ exports.updateMcpServer = async (req, res) => { // MCPService.handleServerUpdate(updatedServer); // Hypothetical function } catch (error) { - console.error(`Error updating MCP server ${id}:`, error); + console.error('Error updating MCP server %s:', id, error); if (error.message.includes('UNIQUE constraint failed')) { return res.status(400).json({ success: false, message: 'An MCP Server with this name already exists.' }); } @@ -180,7 +180,7 @@ exports.deleteMcpServer = async (req, res) => { // MCPService.handleServerDelete(id); // Hypothetical function } catch (error) { - console.error(`Error deleting MCP server ${id}:`, error); + console.error('Error deleting MCP server %s:', id, error); res.status(500).json({ success: false, message: 'Failed to delete MCP server.' }); } }; diff --git a/src/controllers/model/manageController.js b/src/controllers/model/manageController.js index ad62b8b..10c29b3 100644 --- a/src/controllers/model/manageController.js +++ b/src/controllers/model/manageController.js @@ -198,7 +198,7 @@ exports.deleteModel = async (req, res) => { await vllmService.deactivateModel(modelId, gpuId); } } catch (stopError) { - console.error(`Error stopping vLLM process for model ID ${modelId}:`, stopError.message); + console.error('Error stopping vLLM process for model ID %s:', modelId, stopError.message); } await Model.delete(modelId); diff --git a/src/controllers/model/uploadController.js b/src/controllers/model/uploadController.js index af7586b..e6da75b 100644 --- a/src/controllers/model/uploadController.js +++ b/src/controllers/model/uploadController.js @@ -126,14 +126,14 @@ exports.uploadModel = async (req, res) => { }); } catch (dbError) { - console.error(`DB error for model ${name}:`, dbError); + console.error('DB error for model %s:', name, dbError); // Clean up if DB creation failed try { - console.log(`Attempting to delete model file ${modelPath} after DB error.`); + console.log('Attempting to delete model file %s after DB error.', modelPath); await fs.unlink(modelPath); } catch (fileDeleteError) { - console.error(`Failed to delete model file ${modelPath} during cleanup:`, fileDeleteError); + console.error('Failed to delete model file %s during cleanup:', modelPath, fileDeleteError); } // Return error response diff --git a/src/controllers/oauthController.js b/src/controllers/oauthController.js index 5a1147a..a5ab164 100644 --- a/src/controllers/oauthController.js +++ b/src/controllers/oauthController.js @@ -37,7 +37,7 @@ exports.handleOAuthCallback = async (req, res) => { try { tokenData = await exchangeCodeForToken(code, providerConfig, provider); } catch (error) { - console.error(`Error exchanging code for token with ${provider}:`, error); + console.error('Error exchanging code for token with %s:', provider, error); return res.status(401).json({ success: false, message: `Authentication failed with ${provider}` @@ -49,7 +49,7 @@ exports.handleOAuthCallback = async (req, res) => { try { userProfile = await getUserProfile(tokenData.access_token, provider, providerConfig); } catch (error) { - console.error(`Error getting user profile from ${provider}:`, error); + console.error('Error getting user profile from %s:', provider, error); return res.status(401).json({ success: false, message: `Failed to retrieve user profile from ${provider}` diff --git a/src/controllers/userToolConfigController.js b/src/controllers/userToolConfigController.js index a9486c2..fc48e2d 100644 --- a/src/controllers/userToolConfigController.js +++ b/src/controllers/userToolConfigController.js @@ -36,7 +36,7 @@ exports.getUserToolConfig = async (req, res) => { try { configData = JSON.parse(row.config); } catch (parseError) { - console.error(`Error parsing tool config JSON for user ${userId}, tool ${toolName}:`, parseError); + console.error('Error parsing tool config JSON for user %s, tool %s:', userId, toolName, parseError); // Return the raw string if parsing fails? Or return error? Let's return null. return res.status(200).json({ success: true, data: null, warning: 'Stored config is not valid JSON.' }); } @@ -44,7 +44,7 @@ exports.getUserToolConfig = async (req, res) => { res.status(200).json({ success: true, data: configData }); } catch (error) { - console.error(`Error fetching tool config for user ${userId}, tool ${toolName}:`, error); + console.error('Error fetching tool config for user %s, tool %s:', userId, toolName, error); res.status(500).json({ success: false, message: 'Error fetching tool configuration.' }); } }; @@ -72,7 +72,7 @@ exports.saveUserToolConfig = async (req, res) => { // Ensure the config is stored as a JSON string configString = JSON.stringify(config); } catch (stringifyError) { - console.error(`Error stringifying tool config for user ${userId}, tool ${toolName}:`, stringifyError); + console.error('Error stringifying tool config for user %s, tool %s:', userId, toolName, stringifyError); return res.status(400).json({ success: false, message: 'Invalid config object provided.' }); } @@ -104,7 +104,7 @@ exports.saveUserToolConfig = async (req, res) => { res.status(200).json({ success: true, message: 'Configuration saved successfully.', data: updatedConfigData }); } catch (error) { - console.error(`Error saving tool config for user ${userId}, tool ${toolName}:`, error); + console.error('Error saving tool config for user %s, tool %s:', userId, toolName, error); res.status(500).json({ success: false, message: 'Error saving tool configuration.' }); } }; From f5ac053fdd58fc93be0a65441da96797060e988e Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Tue, 24 Feb 2026 08:16:49 +0100 Subject: [PATCH 6/8] update package-lock files --- frontend/package-lock.json | 627 ++++++++++++------------------------- package-lock.json | 397 +++++++++-------------- 2 files changed, 346 insertions(+), 678 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4d0406c..70ada7e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -147,9 +147,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.1.tgz", - "integrity": "sha512-q8rjOuadH0V6Zo4XLMkJ3RMQ9MSBqwaDByyYB0izsYdaIWGNLmEblbCOf1vyFHICcg16CD7Fsi51vcQnYxmt6Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.28.6.tgz", + "integrity": "sha512-QGmsKi2PBO/MHSQk+AAgA9R6OHQr+VqnniFE0eMWZcVcfBZoA2dKn2hUsl3Csg/Plt9opRUWdY7//VXsrIlEiA==", "license": "MIT", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", @@ -2125,54 +2125,42 @@ "license": "MIT" }, "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", - "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", + "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/gast": "11.0.3", - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/gast": "11.1.1", + "@chevrotain/types": "11.1.1", + "lodash-es": "4.17.23" } }, - "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/@chevrotain/gast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", - "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", + "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/types": "11.1.1", + "lodash-es": "4.17.23" } }, - "node_modules/@chevrotain/gast/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", - "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", + "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", - "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", + "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", - "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", + "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", "license": "Apache-2.0" }, "node_modules/@csstools/normalize.css": { @@ -2668,96 +2656,6 @@ "mlly": "^1.8.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -3589,12 +3487,12 @@ "license": "MIT" }, "node_modules/@mermaid-js/parser": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.3.tgz", - "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", + "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", "license": "MIT", "dependencies": { - "langium": "3.3.1" + "langium": "^4.0.0" } }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { @@ -3663,16 +3561,6 @@ "node": ">= 8" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.16.tgz", @@ -5540,9 +5428,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -5573,9 +5461,9 @@ } }, "node_modules/ajv-formats/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==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -5732,17 +5620,19 @@ "license": "MIT" }, "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -6787,17 +6677,17 @@ "license": "MIT" }, "node_modules/chevrotain": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", - "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", + "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/cst-dts-gen": "11.0.3", - "@chevrotain/gast": "11.0.3", - "@chevrotain/regexp-to-ast": "11.0.3", - "@chevrotain/types": "11.0.3", - "@chevrotain/utils": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/cst-dts-gen": "11.1.1", + "@chevrotain/gast": "11.1.1", + "@chevrotain/regexp-to-ast": "11.1.1", + "@chevrotain/types": "11.1.1", + "@chevrotain/utils": "11.1.1", + "lodash-es": "4.17.23" } }, "node_modules/chevrotain-allstar": { @@ -6812,12 +6702,6 @@ "chevrotain": "^11.0.0" } }, - "node_modules/chevrotain/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -8737,12 +8621,6 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "license": "MIT" }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8847,27 +8725,27 @@ } }, "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", @@ -8879,21 +8757,24 @@ "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", + "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", + "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", + "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", @@ -8902,7 +8783,7 @@ "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.18" + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -9207,9 +9088,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "license": "MIT", "dependencies": { "debug": "^3.2.7" @@ -9251,29 +9132,29 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", + "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", - "is-core-module": "^2.15.1", + "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", + "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "engines": { @@ -10042,33 +9923,51 @@ } }, "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.5.tgz", + "integrity": "sha512-ct/ckWBV/9Dg3MlvCXsLcSUyoWwv9mCKqlhLNB2DAuXR/NZolSXlQqP5dyy6guWlPXBhodZyZ5lGPQcbQDxrEQ==", "license": "Apache-2.0", "dependencies": { - "minimatch": "^5.0.1" + "minimatch": "^10.2.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", + "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/filesize": { @@ -10210,34 +10109,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/fork-ts-checker-webpack-plugin": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", @@ -11815,6 +11686,18 @@ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "license": "MIT" }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -12188,31 +12071,15 @@ "node": ">= 0.4" } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", "license": "Apache-2.0", "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", + "async": "^3.2.6", "filelist": "^1.0.4", - "minimatch": "^3.1.2" + "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" @@ -14464,19 +14331,20 @@ } }, "node_modules/langium": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", - "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", + "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", "license": "MIT", "dependencies": { - "chevrotain": "~11.0.3", - "chevrotain-allstar": "~0.3.0", + "chevrotain": "~11.1.1", + "chevrotain-allstar": "~0.3.1", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.0.8" + "vscode-uri": "~3.1.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/language-subtag-registry": { @@ -15110,14 +14978,14 @@ } }, "node_modules/mermaid": { - "version": "11.12.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz", - "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==", + "version": "11.12.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", + "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^0.6.3", + "@mermaid-js/parser": "^1.0.0", "@types/d3": "^7.4.3", "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", @@ -15129,7 +14997,7 @@ "dompurify": "^3.2.5", "katex": "^0.16.22", "khroma": "^2.1.0", - "lodash-es": "^4.17.21", + "lodash-es": "^4.17.23", "marked": "^16.2.1", "roughjs": "^4.6.6", "stylis": "^4.3.6", @@ -15809,9 +15677,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", + "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -15829,15 +15697,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -16340,12 +16199,6 @@ "node": ">=6" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, "node_modules/package-manager-detector": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", @@ -16481,28 +16334,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", @@ -19422,9 +19253,9 @@ } }, "node_modules/schema-utils/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==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -20058,27 +19889,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "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/string-width-cjs/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/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -20232,19 +20042,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "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": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -20353,17 +20150,17 @@ "license": "MIT" }, "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { @@ -20374,15 +20171,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -20392,42 +20180,6 @@ "node": ">= 6" } }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -20885,6 +20637,51 @@ "node": ">=18" } }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -21614,9 +21411,9 @@ "license": "MIT" }, "node_modules/vscode-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", "license": "MIT" }, "node_modules/w3c-hr-time": { @@ -22181,9 +21978,9 @@ } }, "node_modules/workbox-build/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==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -22436,24 +22233,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "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", diff --git a/package-lock.json b/package-lock.json index b3fcd0a..2ea590f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -701,54 +701,42 @@ "license": "MIT" }, "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", - "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", + "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/gast": "11.0.3", - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/gast": "11.1.1", + "@chevrotain/types": "11.1.1", + "lodash-es": "4.17.23" } }, - "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/@chevrotain/gast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", - "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", + "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/types": "11.1.1", + "lodash-es": "4.17.23" } }, - "node_modules/@chevrotain/gast/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", - "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", + "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", - "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", + "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", - "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", + "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", "license": "Apache-2.0" }, "node_modules/@colors/colors": { @@ -1465,45 +1453,13 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/@mermaid-js/parser": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.3.tgz", - "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", + "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", "license": "MIT", "dependencies": { - "langium": "3.3.1" + "langium": "^4.0.0" } }, "node_modules/@modelcontextprotocol/sdk": { @@ -1560,9 +1516,9 @@ } }, "node_modules/@modelcontextprotocol/sdk/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==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -2957,9 +2913,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -2991,9 +2947,9 @@ } }, "node_modules/ajv-formats/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==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -3725,34 +3681,6 @@ "node": ">=10" } }, - "node_modules/cacache/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "optional": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/cacache/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -3964,17 +3892,17 @@ } }, "node_modules/chevrotain": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", - "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", + "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/cst-dts-gen": "11.0.3", - "@chevrotain/gast": "11.0.3", - "@chevrotain/regexp-to-ast": "11.0.3", - "@chevrotain/types": "11.0.3", - "@chevrotain/utils": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/cst-dts-gen": "11.1.1", + "@chevrotain/gast": "11.1.1", + "@chevrotain/regexp-to-ast": "11.1.1", + "@chevrotain/types": "11.1.1", + "@chevrotain/utils": "11.1.1", + "lodash-es": "4.17.23" } }, "node_modules/chevrotain-allstar": { @@ -3989,12 +3917,6 @@ "chevrotain": "^11.0.0" } }, - "node_modules/chevrotain/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -6822,9 +6744,9 @@ "license": "CC0-1.0" }, "node_modules/hono": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", - "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.2.tgz", + "integrity": "sha512-gJnaDHXKDayjt8ue0n8Gs0A007yKXj4Xzb8+cNjZeYsSzzwKc0Lr+OZgYwVfB0pHfUs17EPoLvrOsEaJ9mj+Tg==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -8216,19 +8138,20 @@ "license": "MIT" }, "node_modules/langium": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", - "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", + "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", "license": "MIT", "dependencies": { - "chevrotain": "~11.0.3", - "chevrotain-allstar": "~0.3.0", + "chevrotain": "~11.1.1", + "chevrotain-allstar": "~0.3.1", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.0.8" + "vscode-uri": "~3.1.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/layout-base": { @@ -9219,14 +9142,14 @@ "license": "MIT" }, "node_modules/mermaid": { - "version": "11.12.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz", - "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==", + "version": "11.12.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", + "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^0.6.3", + "@mermaid-js/parser": "^1.0.0", "@types/d3": "^7.4.3", "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", @@ -9238,7 +9161,7 @@ "dompurify": "^3.2.5", "katex": "^0.16.22", "khroma": "^2.1.0", - "lodash-es": "^4.17.21", + "lodash-es": "^4.17.23", "marked": "^16.2.1", "roughjs": "^4.6.6", "stylis": "^4.3.6", @@ -9944,9 +9867,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", + "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -10322,16 +10245,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/node-gyp/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/node-gyp/node_modules/npmlog": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", @@ -10364,31 +10277,6 @@ "node": ">= 6" } }, - "node_modules/node-gyp/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "optional": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC", - "optional": true - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -10404,16 +10292,16 @@ "license": "MIT" }, "node_modules/nodemon": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", - "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^4", "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", + "minimatch": "^10.2.1", "pstree.remy": "^1.1.8", "semver": "^7.5.3", "simple-update-notifier": "^2.0.0", @@ -10432,6 +10320,29 @@ "url": "https://opencollective.com/nodemon" } }, + "node_modules/nodemon/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/nodemon/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -10442,6 +10353,22 @@ "node": ">=4" } }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", + "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -11246,9 +11173,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -12587,44 +12514,12 @@ } } }, - "node_modules/sqlite3/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, "node_modules/sqlite3/node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT" }, - "node_modules/sqlite3/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sqlite3/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", @@ -13016,6 +12911,24 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar-fs": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", @@ -13064,6 +12977,21 @@ "node": ">= 6" } }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -13173,45 +13101,6 @@ "node": ">= 10" } }, - "node_modules/tokenizers/node_modules/tokenizers-android-arm-eabi": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-android-arm64": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-darwin-arm64": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-darwin-x64": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-freebsd-x64": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-linux-arm-gnueabihf": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-linux-arm64-gnu": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-linux-arm64-musl": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-linux-x64-gnu": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-linux-x64-musl": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-win32-arm64-msvc": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-win32-ia32-msvc": { - "optional": true - }, - "node_modules/tokenizers/node_modules/tokenizers-win32-x64-msvc": { - "optional": true - }, "node_modules/touch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", @@ -13708,9 +13597,9 @@ "license": "MIT" }, "node_modules/vscode-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", "license": "MIT" }, "node_modules/walker": { From 15adcfdabb15e1c5916b5bcc8ea86c41ed844a21 Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Fri, 27 Feb 2026 09:30:30 +0100 Subject: [PATCH 7/8] Fixed security issues and tainted path --- scripts/{accelerate.py => check_accelerate.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/{accelerate.py => check_accelerate.py} (100%) diff --git a/scripts/accelerate.py b/scripts/check_accelerate.py similarity index 100% rename from scripts/accelerate.py rename to scripts/check_accelerate.py From 3f35fb0d476bdaba539bf61fa792a8478b801dc0 Mon Sep 17 00:00:00 2001 From: 2pk03 Date: Fri, 27 Feb 2026 09:30:59 +0100 Subject: [PATCH 8/8] Refactor child process execution and improve error handling - Replaced `exec` with `execFile` in multiple utility files for better security and performance. - Updated error logging to use formatted strings for consistency and clarity. - Enhanced URL validation to restrict to internal hosts and prevent SSRF vulnerabilities. - Improved regex patterns for URL extraction to handle a wider range of valid URLs. - Suppressed specific exceptions with logging for better debugging without interrupting flow. - Cleaned up unused imports and optimized code structure for readability. --- .github/codeql/codeql-config.yml | 3 + .github/workflows/codeql-analysis.yml | 3 +- .../src/components/ModelDownloadProgress.jsx | 2 +- .../components/admin/groups/GroupDetails.jsx | 54 +-- .../components/PrimaryModelBanner.jsx | 2 +- .../integrations/ServiceIntegrationsPanel.jsx | 10 +- .../admin/maintenance/DatabaseBackups.jsx | 2 +- .../admin/maintenance/ModelDirectories.jsx | 2 +- .../components/admin/models/ModelEditForm.jsx | 2 - .../admin/models/PrimaryModelCard.jsx | 2 +- .../components/admin/privacy/AirGappedTab.jsx | 6 +- .../admin/privacy/GlobalPrivacyTab.jsx | 4 +- .../components/admin/users/UserManager.jsx | 1 - frontend/src/components/agents/AgentList.jsx | 11 +- frontend/src/components/chat/ChatBubble.jsx | 4 +- frontend/src/components/chat/ChatError.js | 2 +- frontend/src/components/chat/ChatHeader.jsx | 1 - frontend/src/components/chat/ChatList.jsx | 8 +- frontend/src/components/chat/ChatView.jsx | 2 +- frontend/src/pages/SetPasswordPage.jsx | 92 +++-- frontend/src/services/admin/userService.js | 6 +- frontend/src/services/apiService.js | 2 +- frontend/src/services/chatApiService.js | 2 +- frontend/src/services/socketService.js | 24 +- scripts/apply_prompt_format.js | 2 +- scripts/check-model-dirs.js | 9 +- scripts/check_accelerate.py | 4 +- scripts/check_hf_dependencies.js | 347 +++++++++--------- scripts/check_requests_installed.py | 1 - scripts/codeql_summary.py | 36 +- scripts/download_hf_model.py | 24 +- scripts/fix_jwt_secrets.js | 17 +- scripts/gpu-perf/test_streaming.js | 27 +- scripts/huggingface_hub_util.py | 1 - scripts/huggingface_login.py | 4 +- scripts/monitoring/check_llama_gpu.py | 3 +- scripts/persistent_model.py | 8 +- scripts/remove_model_dir.js | 37 +- scripts/reset_admin_password.js | 11 +- scripts/reset_google_models.js | 1 - scripts/run_model.py | 1 - scripts/start_vllm.py | 2 + scripts/test_providers_table.js | 5 +- scripts/torch_util.py | 1 - scripts/tqdm_util.py | 1 - scripts/transformers_util.py | 1 - server.js | 6 +- setup/init-db.js | 7 +- src/config/middleware.js | 8 +- src/config/migrations/000_fix_jwt_secrets.js | 14 +- .../006_add_search_providers_and_configs.js | 4 +- .../migrations/007_add_mcp_tool_permission.js | 1 - ...23_add_grounding_summarization_settings.js | 1 - .../migrations/029_fix_api_providers.js | 3 - .../033_update_group_model_permissions.js | 4 +- src/config/routes.js | 3 - src/config/socket.js | 30 +- src/config/socketHandlers.js | 10 +- .../admin/adminFilteringController.js | 42 ++- src/controllers/admin/adminMcpController.js | 2 +- .../admin/adminProviderController.js | 5 +- .../admin/adminSettingsController.js | 18 +- src/controllers/admin/adminUserController.js | 4 +- src/controllers/agentController.js | 24 +- src/controllers/apiKeyController.js | 15 +- src/controllers/authController.js | 15 +- src/controllers/chatController.js | 53 +-- src/controllers/deepSearchApiController.js | 74 ++-- src/controllers/documentationController.js | 31 +- src/controllers/fileController.js | 105 +++--- src/controllers/groupController.js | 1 - src/controllers/hardwareController.js | 46 ++- src/controllers/huggingFaceController.js | 6 +- src/controllers/integrationController.js | 4 +- src/controllers/internalApiController.js | 10 +- src/controllers/liveSearchApiController.js | 78 ++-- src/controllers/mcpServerController.js | 6 +- src/controllers/model/discoveryController.js | 1 - src/controllers/model/manageController.js | 14 +- .../model/primaryModelController.js | 3 +- src/controllers/model/uploadController.js | 6 +- src/controllers/modelController.js | 46 ++- src/controllers/oauthController.js | 70 ++-- src/controllers/privacyController.js | 4 - src/controllers/scalyticsApiController.js | 8 +- .../systemMaintenanceController.js | 12 +- src/controllers/userToolConfigController.js | 10 +- src/controllers/vectorApiController.js | 8 +- src/mcp_tools/deep_search/deepSearchTool.js | 16 +- src/mcp_tools/live_search/liveSearchTool.js | 14 +- .../live_search/simpleLiveSearchTool.js | 5 +- src/middleware/authMiddleware.js | 64 +--- src/middleware/authScalyticsApiMiddleware.js | 2 +- src/middleware/rateLimitMiddleware.js | 4 +- src/middleware/requestBlocker.js | 7 +- src/models/Permission.js | 2 - src/models/db.js | 22 +- src/models/prompting/filters/defaultFilter.js | 2 +- src/models/prompting/filters/mistralFilter.js | 40 -- src/models/prompting/filters/phiFilter.js | 23 -- src/models/prompting/index.js | 7 +- .../deep_search_service/config.py | 37 +- .../deep_search_service/graph_nodes.py | 90 ++--- .../deep_search_service/main.py | 89 +++-- .../deep_search_service/models.py | 9 +- .../deep_search_service/research_graph.py | 22 +- .../sub_workers/academic_site_handler.py | 14 +- .../sub_workers/content_vector.py | 33 +- .../sub_workers/document_processor.py | 42 +-- .../sub_workers/llm_reasoning.py | 241 ++++++------ .../sub_workers/research_comptroller.py | 19 +- .../sub_workers/research_controller.py | 30 +- .../sub_workers/scrapy_caller.py | 9 +- .../sub_workers/search_scrape.py | 42 +-- .../tests/test_citations.py | 1 - .../deep_search_service/utils/__init__.py | 12 +- .../utils/bot_trap_detector.py | 12 +- .../utils/brave_search_parser.py | 8 +- .../utils/rate_limit_manager.py | 22 +- .../legal_research_nodes.py | 1 - .../live_search_service/config.py | 37 +- .../live_search_service/graph_nodes.py | 6 +- .../live_search_service/main.py | 103 +++--- .../live_search_service/models.py | 9 +- .../live_search_service/research_graph.py | 2 +- .../sub_workers/academic_site_handler.py | 14 +- .../sub_workers/content_vector.py | 59 ++- .../sub_workers/document_processor.py | 42 +-- .../sub_workers/llm_reasoning.py | 248 ++++++------- .../sub_workers/research_comptroller.py | 17 +- .../sub_workers/research_controller.py | 30 +- .../sub_workers/scrapy_caller.py | 9 +- .../sub_workers/search_scrape.py | 44 +-- .../tests/test_citations.py | 1 - .../live_search_service/utils/__init__.py | 4 +- .../utils/brave_search_parser.py | 8 +- .../utils/rate_limit_manager.py | 22 +- src/routes/apiKeyRoutes.js | 2 +- src/routes/chatRoutes.js | 2 +- src/routes/documentationRoutes.js | 1 - src/routes/githubRoutes.js | 4 +- src/routes/modelRoutes.js | 2 +- src/routes/scalyticsApiRoutes.js | 1 - src/services/agents/AgentService.js | 6 - src/services/agents/EmbeddingService.js | 34 +- src/services/agents/MCPService.js | 94 ++--- src/services/apiService.js | 36 +- src/services/authProviderService.js | 2 +- src/services/chatService.js | 31 +- src/services/fileProcessingService.js | 16 +- src/services/filteringWorkerService.js | 20 +- src/services/gpuManager.js | 7 +- .../huggingFaceService/modelDownloader.js | 39 +- src/services/huggingFaceService/modelInfo.js | 2 +- .../huggingFaceService/modelSearch.js | 15 +- src/services/inferenceRouter.js | 14 +- .../databaseBackupService.js | 96 +++-- .../modelDirectoryService.js | 75 ++-- .../maintenanceService/systemInfoService.js | 133 +++---- src/services/modelPoolManager.js | 37 +- src/services/privacyModeManagerService.js | 1 - src/services/providers/anthropic.js | 11 +- src/services/providers/cohere.js | 7 +- src/services/providers/google.js | 73 +--- src/services/providers/handler.js | 15 +- src/services/providers/huggingface.js | 4 - src/services/providers/local.js | 11 +- src/services/providers/mcp.js | 1 - src/services/providers/mistral.js | 5 +- src/services/providers/openai.js | 6 +- src/services/providers/stream.js | 23 +- src/services/providers/xai.js | 19 +- src/services/pythonResearchService.js | 20 +- src/services/vllmService.js | 22 +- src/utils/diskUtils.js | 26 +- src/utils/logUtils.js | 14 + src/utils/modelConfigUtils.js | 21 +- src/utils/modelFileUtils.js | 78 ++-- src/utils/modelUtils.js | 23 +- src/utils/providerConfig.js | 14 +- src/utils/pythonServiceUtils.js | 5 +- src/utils/pythonUtils.js | 73 ++-- src/utils/tokenProcessor.js | 3 +- src/utils/urlValidation.js | 18 +- src/workers/python/deep_search_llm_worker.py | 5 +- src/workers/python/live_search_llm_worker.py | 5 +- src/workers/python/local_model_worker.py | 13 +- .../python/research_controller_worker.py | 22 +- src/workers/python/search_scrape_worker.py | 19 +- test_gemini_hyde.py | 3 +- 190 files changed, 1990 insertions(+), 2437 deletions(-) create mode 100644 .github/codeql/codeql-config.yml create mode 100644 src/utils/logUtils.js diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000..fbaf144 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,3 @@ +paths-ignore: + - '**/node_modules' + - '.tmp' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d0b82c1..ff8dc1e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,8 +30,7 @@ jobs: uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - # If you want to use custom queries, add them here: - # queries: security-extended,security-and-quality + config-file: ./.github/codeql/codeql-config.yml - name: Autobuild uses: github/codeql-action/autobuild@v3 diff --git a/frontend/src/components/ModelDownloadProgress.jsx b/frontend/src/components/ModelDownloadProgress.jsx index a734847..3711f9a 100644 --- a/frontend/src/components/ModelDownloadProgress.jsx +++ b/frontend/src/components/ModelDownloadProgress.jsx @@ -305,7 +305,7 @@ const ModelDownloadProgress = ({ case -1: return 'text-red-600 dark:text-red-400'; default: return 'text-blue-600 dark:text-dark-link'; } - } + }; const getRemainingTime = () => { if (!speed || speed === 0 || !totalBytes || !bytesDownloaded || bytesDownloaded >= totalBytes) { diff --git a/frontend/src/components/admin/groups/GroupDetails.jsx b/frontend/src/components/admin/groups/GroupDetails.jsx index bbb1ce4..a53610d 100644 --- a/frontend/src/components/admin/groups/GroupDetails.jsx +++ b/frontend/src/components/admin/groups/GroupDetails.jsx @@ -139,45 +139,23 @@ const GroupDetails = ({ groupId, onClose }) => { {/* Tab content */}
- {group && group.id !== undefined && ( - <> - {activeTab === 'users' && ( - - )} - {activeTab === 'models' && ( - - )} - {activeTab === 'permissions' && ( - - )} - + {activeTab === 'users' && ( + )} - - {(!group || group.id === undefined) && ( -
-
-
-
- - - -
-
-

Warning

-

Group ID is not defined. Unable to display details.

-
-
-
-
+ {activeTab === 'models' && ( + + )} + {activeTab === 'permissions' && ( + )}
diff --git a/frontend/src/components/admin/huggingface/components/PrimaryModelBanner.jsx b/frontend/src/components/admin/huggingface/components/PrimaryModelBanner.jsx index 1a29f7d..fd8e0da 100644 --- a/frontend/src/components/admin/huggingface/components/PrimaryModelBanner.jsx +++ b/frontend/src/components/admin/huggingface/components/PrimaryModelBanner.jsx @@ -12,7 +12,7 @@ const PrimaryModelBanner = () => { const [primaryModel, setPrimaryModel] = useState(null); const [loading, setLoading] = useState(true); // eslint-disable-next-line no-unused-vars - const [error, setError] = useState(null); + const [, setError] = useState(null); const isMounted = useRef(true); const [visible, setVisible] = useState(false); diff --git a/frontend/src/components/admin/integrations/ServiceIntegrationsPanel.jsx b/frontend/src/components/admin/integrations/ServiceIntegrationsPanel.jsx index e9fb62b..eaf4b9a 100644 --- a/frontend/src/components/admin/integrations/ServiceIntegrationsPanel.jsx +++ b/frontend/src/components/admin/integrations/ServiceIntegrationsPanel.jsx @@ -180,13 +180,13 @@ const ServiceIntegrationsPanel = () => { )} - {/* Empty State or Form */} - {(isCreating || selectedIntegration) ? ( + {/* Form */} + {(isCreating || selectedIntegration) && (

{isCreating ? 'Add New Integration' : 'Edit Integration'}

- + { isLoading={isLoading} />
- ) : (!isCreating && !selectedIntegration && integrations.length === 0) && ( + )} + {/* Empty State */} + {!isCreating && !selectedIntegration && integrations.length === 0 && (
- {backups && Array.isArray(backups) && backups.map((backup) => ( + {backups.map((backup) => (
{backup.fileName} diff --git a/frontend/src/components/admin/maintenance/ModelDirectories.jsx b/frontend/src/components/admin/maintenance/ModelDirectories.jsx index b882ffa..6a15f5c 100644 --- a/frontend/src/components/admin/maintenance/ModelDirectories.jsx +++ b/frontend/src/components/admin/maintenance/ModelDirectories.jsx @@ -56,7 +56,7 @@ const ModelDirectories = ({ - {modelDirectories && Array.isArray(modelDirectories) && modelDirectories.map((dir) => ( + {modelDirectories.map((dir) => (
diff --git a/frontend/src/components/admin/models/ModelEditForm.jsx b/frontend/src/components/admin/models/ModelEditForm.jsx index 952c52f..2f3210a 100644 --- a/frontend/src/components/admin/models/ModelEditForm.jsx +++ b/frontend/src/components/admin/models/ModelEditForm.jsx @@ -376,7 +376,6 @@ const ModelEditForm = ({ {/* vLLM GPU Configuration */} - {!isExternalModel && (

GPU Configuration

@@ -536,7 +535,6 @@ const ModelEditForm = ({
)}
- )}
)} diff --git a/frontend/src/components/admin/models/PrimaryModelCard.jsx b/frontend/src/components/admin/models/PrimaryModelCard.jsx index 70cc8d2..63bc781 100644 --- a/frontend/src/components/admin/models/PrimaryModelCard.jsx +++ b/frontend/src/components/admin/models/PrimaryModelCard.jsx @@ -18,7 +18,7 @@ const PrimaryModelCard = ({ model, onStatusChange }) => { const [loading, setLoading] = useState(true); const [primaryModelData, setPrimaryModelData] = useState(null); // eslint-disable-next-line no-unused-vars - const [intervalId, setIntervalId] = useState(null); + const [, setIntervalId] = useState(null); const [error, setError] = useState(null); const [isSettingPrimary, setIsSettingPrimary] = useState(false); const [isUnsettingPrimary, setIsUnsettingPrimary] = useState(false); diff --git a/frontend/src/components/admin/privacy/AirGappedTab.jsx b/frontend/src/components/admin/privacy/AirGappedTab.jsx index c23da7b..59454b2 100644 --- a/frontend/src/components/admin/privacy/AirGappedTab.jsx +++ b/frontend/src/components/admin/privacy/AirGappedTab.jsx @@ -81,7 +81,7 @@ const AirGappedTab = ({ onSettingChange }) => { } } catch (err) { const errorMsg = `Error toggling air-gapped mode: ${err.response?.data?.message || err.message}.`; - setError(errorMsg || 'Failed to update setting.'); + setError(errorMsg); setIsAirGapped(originalState); } finally { setProcessingToggle(false); @@ -118,10 +118,10 @@ const AirGappedTab = ({ onSettingChange }) => { {/* Standard Button Toggle */} )) ) : ( - isAgentsOpen && ( -
- No MCP agents found. -
- ) +
+ No MCP agents found. +
)}
)} diff --git a/frontend/src/components/chat/ChatBubble.jsx b/frontend/src/components/chat/ChatBubble.jsx index dcff6c4..152c3dc 100644 --- a/frontend/src/components/chat/ChatBubble.jsx +++ b/frontend/src/components/chat/ChatBubble.jsx @@ -524,7 +524,7 @@ const ChatBubble = ({ message, isLoading, streamingContent, onSuggestionClick, r {(() => { let processedSystemContent = processFinalContent(message.content); let personaName = "System Message"; - const personaRegex = /^\[([\w\s-]+(?: - [\w\s-]+)*)\]\s*(.*)/s; + const personaRegex = /^\[([^\]]+)\]\s*(.*)/s; const match = processedSystemContent.match(personaRegex); if (match) { personaName = match[1].trim(); @@ -535,7 +535,7 @@ const ChatBubble = ({ message, isLoading, streamingContent, onSuggestionClick, r
{personaName}
- {String(processedSystemContent || '')} + {String(processedSystemContent)}
diff --git a/frontend/src/components/chat/ChatError.js b/frontend/src/components/chat/ChatError.js index daeddd0..d2a50d0 100644 --- a/frontend/src/components/chat/ChatError.js +++ b/frontend/src/components/chat/ChatError.js @@ -12,7 +12,7 @@ const ChatError = ({ error, onDismiss }) => { if (!error) return null; // Handle both string errors (for backward compatibility) and object errors - const isErrorObject = typeof error === 'object' && error !== null; + const isErrorObject = typeof error === 'object'; const errorMessage = isErrorObject ? error.message : 'Error'; const errorDetail = isErrorObject ? error.detail : error; const errorType = isErrorObject ? error.type : 'general'; diff --git a/frontend/src/components/chat/ChatHeader.jsx b/frontend/src/components/chat/ChatHeader.jsx index 5291f56..5643264 100644 --- a/frontend/src/components/chat/ChatHeader.jsx +++ b/frontend/src/components/chat/ChatHeader.jsx @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import SystemPromptTooltip from '../common/SystemPromptTooltip'; const ChatHeader = ({ isEditing, diff --git a/frontend/src/components/chat/ChatList.jsx b/frontend/src/components/chat/ChatList.jsx index 1a4f780..1fb6138 100644 --- a/frontend/src/components/chat/ChatList.jsx +++ b/frontend/src/components/chat/ChatList.jsx @@ -326,11 +326,9 @@ const ChatList = ({ ); }) ) : ( - isMyChatsOpen && ( -
- No chats yet. Click "New Chat" to start. -
- ) +
+ No chats yet. Click "New Chat" to start. +
)} )} diff --git a/frontend/src/components/chat/ChatView.jsx b/frontend/src/components/chat/ChatView.jsx index 47be7fd..5119bff 100644 --- a/frontend/src/components/chat/ChatView.jsx +++ b/frontend/src/components/chat/ChatView.jsx @@ -269,7 +269,7 @@ const ChatView = ({ chatId, userSettings, onChatUpdated, currentUserId, openShar System Prompt Active )} - {chat && chat.user_id === currentUserId && ( + {chat.user_id === currentUserId && (